Makefile.in (LIBGCOV): Remove.
authorRainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
Fri, 8 Jul 2011 11:43:54 +0000 (11:43 +0000)
committerRainer Orth <ro@gcc.gnu.org>
Fri, 8 Jul 2011 11:43:54 +0000 (11:43 +0000)
gcc:
* Makefile.in (LIBGCOV): Remove.
(libgcc.mvars): Remove LIBGCOV.
* libgov.c: Move to ../libgcc.

libgcc:
* Makfile.in (LIBGCOV): New variable.
($(libgcov-objects)): Use $(srcdir) to refer to libgcov.c.
* libgcov.c: New file.

From-SVN: r176037

gcc/ChangeLog
gcc/Makefile.in
gcc/libgcov.c [deleted file]
libgcc/ChangeLog
libgcc/Makefile.in
libgcc/libgcov.c [new file with mode: 0644]

index 9f0a0e2cab812615d350ca39f6a8e4d6e7e9954c..3c2c2efaba5fe5e69c28d7eeea9c0573ce3fd0b8 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+
+       * Makefile.in (LIBGCOV): Remove.
+       (libgcc.mvars): Remove LIBGCOV.
+       * libgov.c: Move to ../libgcc.
+
 2011-07-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config/fixed-bit.c, config/fixed-bit.h: Move to ../libgcc.
index 0f4a73e7dba85184d4906faad89a8129f41ee9a6..f169a9a357497c039a5e1eb620b121f4b256e753 100644 (file)
@@ -1540,14 +1540,6 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
 # Defined in libgcc2.c, included only in the static library.
 LIB2FUNCS_ST = _eprintf __gcc_bcmp
 
-# Defined in libgcov.c, included only in gcov library
-LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
-    _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
-    _gcov_execv _gcov_execvp _gcov_execve \
-    _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
-    _gcov_indirect_call_profiler _gcov_average_profiler _gcov_ior_profiler \
-    _gcov_merge_ior
-
 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 \
     _lt_sf _le_sf _unord_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
@@ -1933,7 +1925,6 @@ libgcc.mvars: config.status Makefile $(LIB2ADD) $(LIB2ADD_ST) specs \
        echo LIB1ASMSRC = '$(LIB1ASMSRC)' >> tmp-libgcc.mvars
        echo LIB2FUNCS_ST = '$(LIB2FUNCS_ST)' >> tmp-libgcc.mvars
        echo LIB2FUNCS_EXCLUDE = '$(LIB2FUNCS_EXCLUDE)' >> tmp-libgcc.mvars
-       echo LIBGCOV = '$(LIBGCOV)' >> tmp-libgcc.mvars
        echo LIB2ADD = '$(call srcdirify,$(LIB2ADD))' >> tmp-libgcc.mvars
        echo LIB2ADD_ST = '$(call srcdirify,$(LIB2ADD_ST))' >> tmp-libgcc.mvars
        echo LIB2ADDEH = '$(call srcdirify,$(LIB2ADDEH) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
deleted file mode 100644 (file)
index b39ef49..0000000
+++ /dev/null
@@ -1,1003 +0,0 @@
-/* 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, 2004, 2005, 2008, 2009, 2010
-   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 3, or (at your option) any later
-version.
-
-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.
-
-Under Section 7 of GPL version 3, you are granted additional
-permissions described in the GCC Runtime Library Exception, version
-3.1, as published by the Free Software Foundation.
-
-You should have received a copy of the GNU General Public License and
-a copy of the GCC Runtime Library Exception along with this program;
-see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-<http://www.gnu.org/licenses/>.  */
-
-#include "tconfig.h"
-#include "tsystem.h"
-#include "coretypes.h"
-#include "tm.h"
-
-#if defined(inhibit_libc)
-#define IN_LIBGCOV (-1)
-#else
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
-#include <stdio.h>
-#define IN_LIBGCOV 1
-#if defined(L_gcov)
-#define GCOV_LINKAGE /* nothing */
-#endif
-#endif
-#include "gcov-io.h"
-
-#if defined(inhibit_libc)
-/* If libc and its header files are not available, provide dummy functions.  */
-
-#ifdef L_gcov
-void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
-void __gcov_flush (void) {}
-#endif
-
-#ifdef L_gcov_merge_add
-void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
-                      unsigned n_counters __attribute__ ((unused))) {}
-#endif
-
-#ifdef L_gcov_merge_single
-void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
-                         unsigned n_counters __attribute__ ((unused))) {}
-#endif
-
-#ifdef L_gcov_merge_delta
-void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
-                        unsigned n_counters __attribute__ ((unused))) {}
-#endif
-
-#else
-
-#include <string.h>
-#if GCOV_LOCKED
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/stat.h>
-#endif
-
-#ifdef L_gcov
-#include "gcov-io.c"
-
-/* 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 gcov_unsigned_t gcov_crc32;
-
-/* Size of the longest file name. */
-static size_t gcov_max_filename = 0;
-
-/* Make sure path component of the given FILENAME exists, create
-   missing directories. FILENAME must be writable.
-   Returns zero on success, or -1 if an error occurred.  */
-
-static int
-create_file_directory (char *filename)
-{
-#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
-  (void) filename;
-  return -1;
-#else
-  char *s;
-
-  s = filename;
-
-  if (HAS_DRIVE_SPEC(s))
-    s += 2;
-  if (IS_DIR_SEPARATOR(*s))
-    ++s;
-  for (; *s != '\0'; s++)
-    if (IS_DIR_SEPARATOR(*s))
-      {
-        char sep = *s;
-       *s  = '\0';
-
-        /* Try to make directory if it doesn't already exist.  */
-        if (access (filename, F_OK) == -1
-#ifdef TARGET_POSIX_IO
-            && mkdir (filename, 0755) == -1
-#else
-            && mkdir (filename) == -1
-#endif
-            /* The directory might have been made by another process.  */
-           && errno != EEXIST)
-         {
-            fprintf (stderr, "profiling:%s:Cannot create directory\n",
-                    filename);
-            *s = sep;
-           return -1;
-         };
-
-       *s = sep;
-      };
-  return 0;
-#endif
-}
-
-/* Check if VERSION of the info block PTR matches libgcov one.
-   Return 1 on success, or zero in case of versions mismatch.
-   If FILENAME is not NULL, its value used for reporting purposes
-   instead of value from the info block.  */
-
-static int
-gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
-             const char *filename)
-{
-  if (version != GCOV_VERSION)
-    {
-      char v[4], e[4];
-
-      GCOV_UNSIGNED2STRING (v, version);
-      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
-
-      fprintf (stderr,
-              "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-              filename? filename : ptr->filename, e, v);
-      return 0;
-    }
-  return 1;
-}
-
-/* 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 *gi_ptr;
-  struct gcov_summary this_program;
-  struct gcov_summary all;
-  struct gcov_ctr_summary *cs_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-  unsigned t_ix;
-  gcov_unsigned_t c_num;
-  const char *gcov_prefix;
-  int gcov_prefix_strip = 0;
-  size_t prefix_length;
-  char *gi_filename, *gi_filename_up;
-
-  memset (&all, 0, sizeof (all));
-  /* Find the totals for this execution.  */
-  memset (&this_program, 0, sizeof (this_program));
-  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      ci_ptr = gi_ptr->counts;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
-       {
-         if (!((1 << t_ix) & gi_ptr->ctr_mask))
-           continue;
-
-         cs_ptr = &this_program.ctrs[t_ix];
-         cs_ptr->num += ci_ptr->num;
-         for (c_num = 0; c_num < ci_ptr->num; c_num++)
-           {
-             cs_ptr->sum_all += ci_ptr->values[c_num];
-             if (cs_ptr->run_max < ci_ptr->values[c_num])
-               cs_ptr->run_max = ci_ptr->values[c_num];
-           }
-         ci_ptr++;
-       }
-    }
-
-  {
-    /* Check if the level of dirs to strip off specified. */
-    char *tmp = getenv("GCOV_PREFIX_STRIP");
-    if (tmp)
-      {
-       gcov_prefix_strip = atoi (tmp);
-       /* Do not consider negative values. */
-       if (gcov_prefix_strip < 0)
-         gcov_prefix_strip = 0;
-      }
-  }
-  /* Get file name relocation prefix.  Non-absolute values are ignored. */
-  gcov_prefix = getenv("GCOV_PREFIX");
-  if (gcov_prefix)
-    {
-      prefix_length = strlen(gcov_prefix);
-
-      /* Remove an unnecessary trailing '/' */
-      if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
-       prefix_length--;
-    }
-  else
-    prefix_length = 0;
-
-  /* If no prefix was specified and a prefix stip, then we assume
-     relative.  */
-  if (gcov_prefix_strip != 0 && prefix_length == 0)
-    {
-      gcov_prefix = ".";
-      prefix_length = 1;
-    }
-  /* Allocate and initialize the filename scratch space plus one.  */
-  gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 2);
-  if (prefix_length)
-    memcpy (gi_filename, gcov_prefix, prefix_length);
-  gi_filename_up = gi_filename + prefix_length;
-
-  /* Now merge each file.  */
-  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      struct gcov_summary this_object;
-      struct gcov_summary object, program;
-      gcov_type *values[GCOV_COUNTERS];
-      const struct gcov_fn_info *fi_ptr;
-      unsigned fi_stride;
-      unsigned c_ix, f_ix, n_counts;
-      struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
-      int error = 0;
-      gcov_unsigned_t tag, length;
-      gcov_position_t summary_pos = 0;
-      gcov_position_t eof_pos = 0;
-      const char *fname, *s;
-
-      fname = gi_ptr->filename;
-
-      memset (&this_object, 0, sizeof (this_object));
-      memset (&object, 0, sizeof (object));
-
-      /* Avoid to add multiple drive letters into combined path.  */
-      if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
-        fname += 2;
-
-      /* Build relocated filename, stripping off leading
-         directories from the initial filename if requested. */
-      if (gcov_prefix_strip > 0)
-        {
-          int level = 0;
-          s = fname;
-          if (IS_DIR_SEPARATOR(*s))
-            ++s;
-
-          /* Skip selected directory levels. */
-         for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
-           if (IS_DIR_SEPARATOR(*s))
-             {
-               fname = s;
-               level++;
-             }
-        }
-      /* Update complete filename with stripped original. */
-      if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
-        {
-          /* If prefix is given, add directory separator.  */
-         strcpy (gi_filename_up, "/");
-         strcpy (gi_filename_up + 1, fname);
-       }
-      else
-        strcpy (gi_filename_up, fname);
-
-      /* Totals for this object file.  */
-      ci_ptr = gi_ptr->counts;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
-       {
-         if (!((1 << t_ix) & gi_ptr->ctr_mask))
-           continue;
-
-         cs_ptr = &this_object.ctrs[t_ix];
-         cs_ptr->num += ci_ptr->num;
-         for (c_num = 0; c_num < ci_ptr->num; c_num++)
-           {
-             cs_ptr->sum_all += ci_ptr->values[c_num];
-             if (cs_ptr->run_max < ci_ptr->values[c_num])
-               cs_ptr->run_max = ci_ptr->values[c_num];
-           }
-
-         ci_ptr++;
-       }
-
-      c_ix = 0;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-       if ((1 << t_ix) & gi_ptr->ctr_mask)
-         {
-           values[c_ix] = gi_ptr->counts[c_ix].values;
-           c_ix++;
-         }
-
-      /* Calculate the function_info stride. This depends on the
-        number of counter types being measured.  */
-      fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
-      if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
-       {
-         fi_stride += __alignof__ (struct gcov_fn_info) - 1;
-         fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
-       }
-
-      if (!gcov_open (gi_filename))
-       {
-         /* Open failed likely due to missed directory.
-            Create directory and retry to open file. */
-          if (create_file_directory (gi_filename))
-           {
-             fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
-             continue;
-           }
-         if (!gcov_open (gi_filename))
-           {
-              fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
-             continue;
-           }
-       }
-
-      tag = gcov_read_unsigned ();
-      if (tag)
-       {
-         /* Merge data from file.  */
-         if (tag != GCOV_DATA_MAGIC)
-           {
-             fprintf (stderr, "profiling:%s:Not a gcov data file\n",
-                      gi_filename);
-             goto read_fatal;
-           }
-         length = gcov_read_unsigned ();
-         if (!gcov_version (gi_ptr, length, gi_filename))
-           goto read_fatal;
-
-         length = gcov_read_unsigned ();
-         if (length != gi_ptr->stamp)
-           /* Read from a different compilation. Overwrite the file.  */
-           goto rewrite;
-
-         /* Merge execution counts for each function.  */
-         for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-           {
-             fi_ptr = (const struct gcov_fn_info *)
-                     ((const char *) gi_ptr->functions + f_ix * fi_stride);
-             tag = gcov_read_unsigned ();
-             length = gcov_read_unsigned ();
-
-             /* Check function.  */
-             if (tag != GCOV_TAG_FUNCTION
-                 || length != GCOV_TAG_FUNCTION_LENGTH
-                 || gcov_read_unsigned () != fi_ptr->ident
-                 || gcov_read_unsigned () != fi_ptr->lineno_checksum
-                 || gcov_read_unsigned () != fi_ptr->cfg_checksum)
-               {
-               read_mismatch:;
-                 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
-                          gi_filename,
-                          f_ix + 1 ? "function" : "summaries");
-                 goto read_fatal;
-               }
-
-             c_ix = 0;
-             for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-               {
-                 gcov_merge_fn merge;
-
-                 if (!((1 << t_ix) & gi_ptr->ctr_mask))
-                   continue;
-
-                 n_counts = fi_ptr->n_ctrs[c_ix];
-                 merge = gi_ptr->counts[c_ix].merge;
-
-                 tag = gcov_read_unsigned ();
-                 length = gcov_read_unsigned ();
-                 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
-                     || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
-                   goto read_mismatch;
-                 (*merge) (values[c_ix], n_counts);
-                 values[c_ix] += n_counts;
-                 c_ix++;
-               }
-             if ((error = gcov_is_error ()))
-               goto read_error;
-           }
-
-         f_ix = ~0u;
-         /* Check program & object summary */
-         while (1)
-           {
-             int is_program;
-
-             eof_pos = gcov_position ();
-             tag = gcov_read_unsigned ();
-             if (!tag)
-               break;
-
-             length = gcov_read_unsigned ();
-             is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
-             if (length != GCOV_TAG_SUMMARY_LENGTH
-                 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
-               goto read_mismatch;
-             gcov_read_summary (is_program ? &program : &object);
-             if ((error = gcov_is_error ()))
-               goto read_error;
-             if (is_program && program.checksum == gcov_crc32)
-               {
-                 summary_pos = eof_pos;
-                 goto rewrite;
-               }
-           }
-       }
-      goto rewrite;
-
-    read_error:;
-      fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
-              : "profiling:%s:Error merging\n", gi_filename);
-
-    read_fatal:;
-      gcov_close ();
-      continue;
-
-    rewrite:;
-      gcov_rewrite ();
-      if (!summary_pos)
-       memset (&program, 0, sizeof (program));
-
-      /* Merge the summaries.  */
-      f_ix = ~0u;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
-       {
-         cs_obj = &object.ctrs[t_ix];
-         cs_tobj = &this_object.ctrs[t_ix];
-         cs_prg = &program.ctrs[t_ix];
-         cs_tprg = &this_program.ctrs[t_ix];
-         cs_all = &all.ctrs[t_ix];
-
-         if ((1 << t_ix) & gi_ptr->ctr_mask)
-           {
-             if (!cs_obj->runs++)
-               cs_obj->num = cs_tobj->num;
-             else if (cs_obj->num != cs_tobj->num)
-               goto read_mismatch;
-             cs_obj->sum_all += cs_tobj->sum_all;
-             if (cs_obj->run_max < cs_tobj->run_max)
-               cs_obj->run_max = cs_tobj->run_max;
-             cs_obj->sum_max += cs_tobj->run_max;
-
-             if (!cs_prg->runs++)
-               cs_prg->num = cs_tprg->num;
-             else if (cs_prg->num != cs_tprg->num)
-               goto read_mismatch;
-             cs_prg->sum_all += cs_tprg->sum_all;
-             if (cs_prg->run_max < cs_tprg->run_max)
-               cs_prg->run_max = cs_tprg->run_max;
-             cs_prg->sum_max += cs_tprg->run_max;
-           }
-         else if (cs_obj->num || cs_prg->num)
-           goto read_mismatch;
-
-         if (!cs_all->runs && cs_prg->runs)
-           memcpy (cs_all, cs_prg, sizeof (*cs_all));
-         else if (!all.checksum
-                  && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
-                  && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
-           {
-             fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
-                      gi_filename, GCOV_LOCKED
-                      ? "" : " or concurrent update without locking support");
-             all.checksum = ~0u;
-           }
-       }
-
-      c_ix = 0;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-       if ((1 << t_ix) & gi_ptr->ctr_mask)
-         {
-           values[c_ix] = gi_ptr->counts[c_ix].values;
-           c_ix++;
-         }
-
-      program.checksum = gcov_crc32;
-
-      /* Write out the data.  */
-      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
-      gcov_write_unsigned (gi_ptr->stamp);
-
-      /* Write execution counts for each function.  */
-      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-       {
-         fi_ptr = (const struct gcov_fn_info *)
-                 ((const char *) gi_ptr->functions + f_ix * fi_stride);
-
-         /* Announce function.  */
-         gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
-         gcov_write_unsigned (fi_ptr->ident);
-         gcov_write_unsigned (fi_ptr->lineno_checksum);
-         gcov_write_unsigned (fi_ptr->cfg_checksum);
-
-         c_ix = 0;
-         for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-           {
-             gcov_type *c_ptr;
-
-             if (!((1 << t_ix) & gi_ptr->ctr_mask))
-               continue;
-
-             n_counts = fi_ptr->n_ctrs[c_ix];
-
-             gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-                                    GCOV_TAG_COUNTER_LENGTH (n_counts));
-             c_ptr = values[c_ix];
-             while (n_counts--)
-               gcov_write_counter (*c_ptr++);
-
-             values[c_ix] = c_ptr;
-             c_ix++;
-           }
-       }
-
-      /* Object file summary.  */
-      gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
-
-      /* Generate whole program statistics.  */
-      if (eof_pos)
-       gcov_seek (eof_pos);
-      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
-      if (!summary_pos)
-       gcov_write_unsigned (0);
-      if ((error = gcov_close ()))
-         fprintf (stderr, error  < 0 ?
-                  "profiling:%s:Overflow writing\n" :
-                  "profiling:%s:Error writing\n",
-                  gi_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 (gcov_version (info, info->version, 0))
-    {
-      const char *ptr = info->filename;
-      gcov_unsigned_t crc32 = gcov_crc32;
-      size_t filename_length =  strlen(info->filename);
-
-      /* Refresh the longest file name information */
-      if (filename_length > gcov_max_filename)
-        gcov_max_filename = filename_length;
-
-      do
-       {
-         unsigned ix;
-         gcov_unsigned_t value = *ptr << 24;
-
-         for (ix = 8; ix--; value <<= 1)
-           {
-             gcov_unsigned_t 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)
-{
-  const struct gcov_info *gi_ptr;
-
-  gcov_exit ();
-  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      unsigned t_ix;
-      const struct gcov_ctr_info *ci_ptr;
-
-      for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
-       if ((1 << t_ix) & gi_ptr->ctr_mask)
-         {
-           memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
-           ci_ptr++;
-         }
-    }
-}
-
-#endif /* L_gcov */
-
-#ifdef L_gcov_merge_add
-/* The profile merging function that just adds the counters.  It is given
-   an array COUNTERS of N_COUNTERS old counters and it reads the same number
-   of counters from the gcov file.  */
-void
-__gcov_merge_add (gcov_type *counters, unsigned n_counters)
-{
-  for (; n_counters; counters++, n_counters--)
-    *counters += gcov_read_counter ();
-}
-#endif /* L_gcov_merge_add */
-
-#ifdef L_gcov_merge_ior
-/* The profile merging function that just adds the counters.  It is given
-   an array COUNTERS of N_COUNTERS old counters and it reads the same number
-   of counters from the gcov file.  */
-void
-__gcov_merge_ior (gcov_type *counters, unsigned n_counters)
-{
-  for (; n_counters; counters++, n_counters--)
-    *counters |= gcov_read_counter ();
-}
-#endif
-
-#ifdef L_gcov_merge_single
-/* The profile merging function for choosing the most common value.
-   It is given an array COUNTERS of N_COUNTERS old counters and it
-   reads the same number of counters from the gcov file.  The counters
-   are split into 3-tuples where the members of the tuple have
-   meanings:
-
-   -- the stored candidate on the most common value of the measured entity
-   -- counter
-   -- total number of evaluations of the value  */
-void
-__gcov_merge_single (gcov_type *counters, unsigned n_counters)
-{
-  unsigned i, n_measures;
-  gcov_type value, counter, all;
-
-  gcc_assert (!(n_counters % 3));
-  n_measures = n_counters / 3;
-  for (i = 0; i < n_measures; i++, counters += 3)
-    {
-      value = gcov_read_counter ();
-      counter = gcov_read_counter ();
-      all = gcov_read_counter ();
-
-      if (counters[0] == value)
-       counters[1] += counter;
-      else if (counter > counters[1])
-       {
-         counters[0] = value;
-         counters[1] = counter - counters[1];
-       }
-      else
-       counters[1] -= counter;
-      counters[2] += all;
-    }
-}
-#endif /* L_gcov_merge_single */
-
-#ifdef L_gcov_merge_delta
-/* The profile merging function for choosing the most common
-   difference between two consecutive evaluations of the value.  It is
-   given an array COUNTERS of N_COUNTERS old counters and it reads the
-   same number of counters from the gcov file.  The counters are split
-   into 4-tuples where the members of the tuple have meanings:
-
-   -- the last value of the measured entity
-   -- the stored candidate on the most common difference
-   -- counter
-   -- total number of evaluations of the value  */
-void
-__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
-{
-  unsigned i, n_measures;
-  gcov_type value, counter, all;
-
-  gcc_assert (!(n_counters % 4));
-  n_measures = n_counters / 4;
-  for (i = 0; i < n_measures; i++, counters += 4)
-    {
-      /* last = */ gcov_read_counter ();
-      value = gcov_read_counter ();
-      counter = gcov_read_counter ();
-      all = gcov_read_counter ();
-
-      if (counters[1] == value)
-       counters[2] += counter;
-      else if (counter > counters[2])
-       {
-         counters[1] = value;
-         counters[2] = counter - counters[2];
-       }
-      else
-       counters[2] -= counter;
-      counters[3] += all;
-    }
-}
-#endif /* L_gcov_merge_delta */
-
-#ifdef L_gcov_interval_profiler
-/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
-   corresponding counter in COUNTERS.  If the VALUE is above or below
-   the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
-   instead.  */
-
-void
-__gcov_interval_profiler (gcov_type *counters, gcov_type value,
-                         int start, unsigned steps)
-{
-  gcov_type delta = value - start;
-  if (delta < 0)
-    counters[steps + 1]++;
-  else if (delta >= steps)
-    counters[steps]++;
-  else
-    counters[delta]++;
-}
-#endif
-
-#ifdef L_gcov_pow2_profiler
-/* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
-   COUNTERS[0] is incremented.  */
-
-void
-__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
-{
-  if (value & (value - 1))
-    counters[0]++;
-  else
-    counters[1]++;
-}
-#endif
-
-/* Tries to determine the most common value among its inputs.  Checks if the
-   value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
-   is incremented.  If this is not the case and COUNTERS[1] is not zero,
-   COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
-   VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
-   function is called more than 50% of the time with one value, this value
-   will be in COUNTERS[0] in the end.
-
-   In any case, COUNTERS[2] is incremented.  */
-
-static inline void
-__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
-{
-  if (value == counters[0])
-    counters[1]++;
-  else if (counters[1] == 0)
-    {
-      counters[1] = 1;
-      counters[0] = value;
-    }
-  else
-    counters[1]--;
-  counters[2]++;
-}
-
-#ifdef L_gcov_one_value_profiler
-void
-__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
-{
-  __gcov_one_value_profiler_body (counters, value);
-}
-#endif
-
-#ifdef L_gcov_indirect_call_profiler
-
-/* By default, the C++ compiler will use function addresses in the
-   vtable entries.  Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
-   tells the compiler to use function descriptors instead.  The value
-   of this macro says how many words wide the descriptor is (normally 2),
-   but it may be dependent on target flags.  Since we do not have access
-   to the target flags here we just check to see if it is set and use
-   that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
-
-   It is assumed that the address of a function descriptor may be treated
-   as a pointer to a function.  */
-
-#ifdef TARGET_VTABLE_USES_DESCRIPTORS
-#define VTABLE_USES_DESCRIPTORS 1
-#else
-#define VTABLE_USES_DESCRIPTORS 0
-#endif
-
-/* Tries to determine the most common value among its inputs. */
-void
-__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
-                              void* cur_func, void* callee_func)
-{
-  /* If the C++ virtual tables contain function descriptors then one
-     function may have multiple descriptors and we need to dereference
-     the descriptors to see if they point to the same function.  */
-  if (cur_func == callee_func
-      || (VTABLE_USES_DESCRIPTORS && callee_func
-         && *(void **) cur_func == *(void **) callee_func))
-    __gcov_one_value_profiler_body (counter, value);
-}
-#endif
-
-
-#ifdef L_gcov_average_profiler
-/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
-   to saturate up.  */
-
-void
-__gcov_average_profiler (gcov_type *counters, gcov_type value)
-{
-  counters[0] += value;
-  counters[1] ++;
-}
-#endif
-
-#ifdef L_gcov_ior_profiler
-/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
-   to saturate up.  */
-
-void
-__gcov_ior_profiler (gcov_type *counters, gcov_type value)
-{
-  *counters |= value;
-}
-#endif
-
-#ifdef L_gcov_fork
-/* A wrapper for the fork function.  Flushes the accumulated profiling data, so
-   that they are not counted twice.  */
-
-pid_t
-__gcov_fork (void)
-{
-  __gcov_flush ();
-  return fork ();
-}
-#endif
-
-#ifdef L_gcov_execl
-/* A wrapper for the execl function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execl (const char *path, char *arg, ...)
-{
-  va_list ap, aq;
-  unsigned i, length;
-  char **args;
-
-  __gcov_flush ();
-
-  va_start (ap, arg);
-  va_copy (aq, ap);
-
-  length = 2;
-  while (va_arg (ap, char *))
-    length++;
-  va_end (ap);
-
-  args = (char **) alloca (length * sizeof (void *));
-  args[0] = arg;
-  for (i = 1; i < length; i++)
-    args[i] = va_arg (aq, char *);
-  va_end (aq);
-
-  return execv (path, args);
-}
-#endif
-
-#ifdef L_gcov_execlp
-/* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execlp (const char *path, char *arg, ...)
-{
-  va_list ap, aq;
-  unsigned i, length;
-  char **args;
-
-  __gcov_flush ();
-
-  va_start (ap, arg);
-  va_copy (aq, ap);
-
-  length = 2;
-  while (va_arg (ap, char *))
-    length++;
-  va_end (ap);
-
-  args = (char **) alloca (length * sizeof (void *));
-  args[0] = arg;
-  for (i = 1; i < length; i++)
-    args[i] = va_arg (aq, char *);
-  va_end (aq);
-
-  return execvp (path, args);
-}
-#endif
-
-#ifdef L_gcov_execle
-/* A wrapper for the execle function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execle (const char *path, char *arg, ...)
-{
-  va_list ap, aq;
-  unsigned i, length;
-  char **args;
-  char **envp;
-
-  __gcov_flush ();
-
-  va_start (ap, arg);
-  va_copy (aq, ap);
-
-  length = 2;
-  while (va_arg (ap, char *))
-    length++;
-  va_end (ap);
-
-  args = (char **) alloca (length * sizeof (void *));
-  args[0] = arg;
-  for (i = 1; i < length; i++)
-    args[i] = va_arg (aq, char *);
-  envp = va_arg (aq, char **);
-  va_end (aq);
-
-  return execve (path, args, envp);
-}
-#endif
-
-#ifdef L_gcov_execv
-/* A wrapper for the execv function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execv (const char *path, char *const argv[])
-{
-  __gcov_flush ();
-  return execv (path, argv);
-}
-#endif
-
-#ifdef L_gcov_execvp
-/* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execvp (const char *path, char *const argv[])
-{
-  __gcov_flush ();
-  return execvp (path, argv);
-}
-#endif
-
-#ifdef L_gcov_execve
-/* A wrapper for the execve function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
-
-int
-__gcov_execve (const char *path, char *const argv[], char *const envp[])
-{
-  __gcov_flush ();
-  return execve (path, argv, envp);
-}
-#endif
-#endif /* inhibit_libc */
index 091e674b1884f6f1d29dd46019d75afcaeb059ab..a09b88a8c388fa21d8daf049541bdfc3ffdd7100 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
+
+       * Makfile.in (LIBGCOV): New variable.
+       ($(libgcov-objects)): Use $(srcdir) to refer to libgcov.c.
+       * libgcov.c: New file.
+
 2011-07-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * fixed-bit.c, fixed-bit.h: New files.
index d0a1d1582ee638965340494fc47a8b76fd53aa7c..e204ef02ac12badcb84a4c392bc2aeb042b08bcd 100644 (file)
@@ -747,9 +747,19 @@ iter-items := $(LIBUNWIND)
 include $(iterator)
 
 # Build libgcov components.
+
+# Defined in libgcov.c, included only in gcov library
+LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
+    _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
+    _gcov_execv _gcov_execvp _gcov_execve \
+    _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
+    _gcov_indirect_call_profiler _gcov_average_profiler _gcov_ior_profiler \
+    _gcov_merge_ior
+
 libgcov-objects = $(patsubst %,%$(objext),$(LIBGCOV))
-$(libgcov-objects): %$(objext): $(gcc_srcdir)/libgcov.c
-       $(gcc_compile) -DL$* -c $(gcc_srcdir)/libgcov.c
+
+$(libgcov-objects): %$(objext): $(srcdir)/libgcov.c
+       $(gcc_compile) -DL$* -c $(srcdir)/libgcov.c
 
 
 # Static libraries.
diff --git a/libgcc/libgcov.c b/libgcc/libgcov.c
new file mode 100644 (file)
index 0000000..b39ef49
--- /dev/null
@@ -0,0 +1,1003 @@
+/* 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, 2004, 2005, 2008, 2009, 2010
+   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 3, or (at your option) any later
+version.
+
+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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+
+#if defined(inhibit_libc)
+#define IN_LIBGCOV (-1)
+#else
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+#define IN_LIBGCOV 1
+#if defined(L_gcov)
+#define GCOV_LINKAGE /* nothing */
+#endif
+#endif
+#include "gcov-io.h"
+
+#if defined(inhibit_libc)
+/* If libc and its header files are not available, provide dummy functions.  */
+
+#ifdef L_gcov
+void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
+void __gcov_flush (void) {}
+#endif
+
+#ifdef L_gcov_merge_add
+void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
+                      unsigned n_counters __attribute__ ((unused))) {}
+#endif
+
+#ifdef L_gcov_merge_single
+void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
+                         unsigned n_counters __attribute__ ((unused))) {}
+#endif
+
+#ifdef L_gcov_merge_delta
+void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
+                        unsigned n_counters __attribute__ ((unused))) {}
+#endif
+
+#else
+
+#include <string.h>
+#if GCOV_LOCKED
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef L_gcov
+#include "gcov-io.c"
+
+/* 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 gcov_unsigned_t gcov_crc32;
+
+/* Size of the longest file name. */
+static size_t gcov_max_filename = 0;
+
+/* Make sure path component of the given FILENAME exists, create
+   missing directories. FILENAME must be writable.
+   Returns zero on success, or -1 if an error occurred.  */
+
+static int
+create_file_directory (char *filename)
+{
+#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
+  (void) filename;
+  return -1;
+#else
+  char *s;
+
+  s = filename;
+
+  if (HAS_DRIVE_SPEC(s))
+    s += 2;
+  if (IS_DIR_SEPARATOR(*s))
+    ++s;
+  for (; *s != '\0'; s++)
+    if (IS_DIR_SEPARATOR(*s))
+      {
+        char sep = *s;
+       *s  = '\0';
+
+        /* Try to make directory if it doesn't already exist.  */
+        if (access (filename, F_OK) == -1
+#ifdef TARGET_POSIX_IO
+            && mkdir (filename, 0755) == -1
+#else
+            && mkdir (filename) == -1
+#endif
+            /* The directory might have been made by another process.  */
+           && errno != EEXIST)
+         {
+            fprintf (stderr, "profiling:%s:Cannot create directory\n",
+                    filename);
+            *s = sep;
+           return -1;
+         };
+
+       *s = sep;
+      };
+  return 0;
+#endif
+}
+
+/* Check if VERSION of the info block PTR matches libgcov one.
+   Return 1 on success, or zero in case of versions mismatch.
+   If FILENAME is not NULL, its value used for reporting purposes
+   instead of value from the info block.  */
+
+static int
+gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
+             const char *filename)
+{
+  if (version != GCOV_VERSION)
+    {
+      char v[4], e[4];
+
+      GCOV_UNSIGNED2STRING (v, version);
+      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
+
+      fprintf (stderr,
+              "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
+              filename? filename : ptr->filename, e, v);
+      return 0;
+    }
+  return 1;
+}
+
+/* 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 *gi_ptr;
+  struct gcov_summary this_program;
+  struct gcov_summary all;
+  struct gcov_ctr_summary *cs_ptr;
+  const struct gcov_ctr_info *ci_ptr;
+  unsigned t_ix;
+  gcov_unsigned_t c_num;
+  const char *gcov_prefix;
+  int gcov_prefix_strip = 0;
+  size_t prefix_length;
+  char *gi_filename, *gi_filename_up;
+
+  memset (&all, 0, sizeof (all));
+  /* Find the totals for this execution.  */
+  memset (&this_program, 0, sizeof (this_program));
+  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      ci_ptr = gi_ptr->counts;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+       {
+         if (!((1 << t_ix) & gi_ptr->ctr_mask))
+           continue;
+
+         cs_ptr = &this_program.ctrs[t_ix];
+         cs_ptr->num += ci_ptr->num;
+         for (c_num = 0; c_num < ci_ptr->num; c_num++)
+           {
+             cs_ptr->sum_all += ci_ptr->values[c_num];
+             if (cs_ptr->run_max < ci_ptr->values[c_num])
+               cs_ptr->run_max = ci_ptr->values[c_num];
+           }
+         ci_ptr++;
+       }
+    }
+
+  {
+    /* Check if the level of dirs to strip off specified. */
+    char *tmp = getenv("GCOV_PREFIX_STRIP");
+    if (tmp)
+      {
+       gcov_prefix_strip = atoi (tmp);
+       /* Do not consider negative values. */
+       if (gcov_prefix_strip < 0)
+         gcov_prefix_strip = 0;
+      }
+  }
+  /* Get file name relocation prefix.  Non-absolute values are ignored. */
+  gcov_prefix = getenv("GCOV_PREFIX");
+  if (gcov_prefix)
+    {
+      prefix_length = strlen(gcov_prefix);
+
+      /* Remove an unnecessary trailing '/' */
+      if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
+       prefix_length--;
+    }
+  else
+    prefix_length = 0;
+
+  /* If no prefix was specified and a prefix stip, then we assume
+     relative.  */
+  if (gcov_prefix_strip != 0 && prefix_length == 0)
+    {
+      gcov_prefix = ".";
+      prefix_length = 1;
+    }
+  /* Allocate and initialize the filename scratch space plus one.  */
+  gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 2);
+  if (prefix_length)
+    memcpy (gi_filename, gcov_prefix, prefix_length);
+  gi_filename_up = gi_filename + prefix_length;
+
+  /* Now merge each file.  */
+  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      struct gcov_summary this_object;
+      struct gcov_summary object, program;
+      gcov_type *values[GCOV_COUNTERS];
+      const struct gcov_fn_info *fi_ptr;
+      unsigned fi_stride;
+      unsigned c_ix, f_ix, n_counts;
+      struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
+      int error = 0;
+      gcov_unsigned_t tag, length;
+      gcov_position_t summary_pos = 0;
+      gcov_position_t eof_pos = 0;
+      const char *fname, *s;
+
+      fname = gi_ptr->filename;
+
+      memset (&this_object, 0, sizeof (this_object));
+      memset (&object, 0, sizeof (object));
+
+      /* Avoid to add multiple drive letters into combined path.  */
+      if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
+        fname += 2;
+
+      /* Build relocated filename, stripping off leading
+         directories from the initial filename if requested. */
+      if (gcov_prefix_strip > 0)
+        {
+          int level = 0;
+          s = fname;
+          if (IS_DIR_SEPARATOR(*s))
+            ++s;
+
+          /* Skip selected directory levels. */
+         for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
+           if (IS_DIR_SEPARATOR(*s))
+             {
+               fname = s;
+               level++;
+             }
+        }
+      /* Update complete filename with stripped original. */
+      if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
+        {
+          /* If prefix is given, add directory separator.  */
+         strcpy (gi_filename_up, "/");
+         strcpy (gi_filename_up + 1, fname);
+       }
+      else
+        strcpy (gi_filename_up, fname);
+
+      /* Totals for this object file.  */
+      ci_ptr = gi_ptr->counts;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+       {
+         if (!((1 << t_ix) & gi_ptr->ctr_mask))
+           continue;
+
+         cs_ptr = &this_object.ctrs[t_ix];
+         cs_ptr->num += ci_ptr->num;
+         for (c_num = 0; c_num < ci_ptr->num; c_num++)
+           {
+             cs_ptr->sum_all += ci_ptr->values[c_num];
+             if (cs_ptr->run_max < ci_ptr->values[c_num])
+               cs_ptr->run_max = ci_ptr->values[c_num];
+           }
+
+         ci_ptr++;
+       }
+
+      c_ix = 0;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+       if ((1 << t_ix) & gi_ptr->ctr_mask)
+         {
+           values[c_ix] = gi_ptr->counts[c_ix].values;
+           c_ix++;
+         }
+
+      /* Calculate the function_info stride. This depends on the
+        number of counter types being measured.  */
+      fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
+      if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
+       {
+         fi_stride += __alignof__ (struct gcov_fn_info) - 1;
+         fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
+       }
+
+      if (!gcov_open (gi_filename))
+       {
+         /* Open failed likely due to missed directory.
+            Create directory and retry to open file. */
+          if (create_file_directory (gi_filename))
+           {
+             fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
+             continue;
+           }
+         if (!gcov_open (gi_filename))
+           {
+              fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
+             continue;
+           }
+       }
+
+      tag = gcov_read_unsigned ();
+      if (tag)
+       {
+         /* Merge data from file.  */
+         if (tag != GCOV_DATA_MAGIC)
+           {
+             fprintf (stderr, "profiling:%s:Not a gcov data file\n",
+                      gi_filename);
+             goto read_fatal;
+           }
+         length = gcov_read_unsigned ();
+         if (!gcov_version (gi_ptr, length, gi_filename))
+           goto read_fatal;
+
+         length = gcov_read_unsigned ();
+         if (length != gi_ptr->stamp)
+           /* Read from a different compilation. Overwrite the file.  */
+           goto rewrite;
+
+         /* Merge execution counts for each function.  */
+         for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+           {
+             fi_ptr = (const struct gcov_fn_info *)
+                     ((const char *) gi_ptr->functions + f_ix * fi_stride);
+             tag = gcov_read_unsigned ();
+             length = gcov_read_unsigned ();
+
+             /* Check function.  */
+             if (tag != GCOV_TAG_FUNCTION
+                 || length != GCOV_TAG_FUNCTION_LENGTH
+                 || gcov_read_unsigned () != fi_ptr->ident
+                 || gcov_read_unsigned () != fi_ptr->lineno_checksum
+                 || gcov_read_unsigned () != fi_ptr->cfg_checksum)
+               {
+               read_mismatch:;
+                 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
+                          gi_filename,
+                          f_ix + 1 ? "function" : "summaries");
+                 goto read_fatal;
+               }
+
+             c_ix = 0;
+             for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+               {
+                 gcov_merge_fn merge;
+
+                 if (!((1 << t_ix) & gi_ptr->ctr_mask))
+                   continue;
+
+                 n_counts = fi_ptr->n_ctrs[c_ix];
+                 merge = gi_ptr->counts[c_ix].merge;
+
+                 tag = gcov_read_unsigned ();
+                 length = gcov_read_unsigned ();
+                 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
+                     || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
+                   goto read_mismatch;
+                 (*merge) (values[c_ix], n_counts);
+                 values[c_ix] += n_counts;
+                 c_ix++;
+               }
+             if ((error = gcov_is_error ()))
+               goto read_error;
+           }
+
+         f_ix = ~0u;
+         /* Check program & object summary */
+         while (1)
+           {
+             int is_program;
+
+             eof_pos = gcov_position ();
+             tag = gcov_read_unsigned ();
+             if (!tag)
+               break;
+
+             length = gcov_read_unsigned ();
+             is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
+             if (length != GCOV_TAG_SUMMARY_LENGTH
+                 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
+               goto read_mismatch;
+             gcov_read_summary (is_program ? &program : &object);
+             if ((error = gcov_is_error ()))
+               goto read_error;
+             if (is_program && program.checksum == gcov_crc32)
+               {
+                 summary_pos = eof_pos;
+                 goto rewrite;
+               }
+           }
+       }
+      goto rewrite;
+
+    read_error:;
+      fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
+              : "profiling:%s:Error merging\n", gi_filename);
+
+    read_fatal:;
+      gcov_close ();
+      continue;
+
+    rewrite:;
+      gcov_rewrite ();
+      if (!summary_pos)
+       memset (&program, 0, sizeof (program));
+
+      /* Merge the summaries.  */
+      f_ix = ~0u;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+       {
+         cs_obj = &object.ctrs[t_ix];
+         cs_tobj = &this_object.ctrs[t_ix];
+         cs_prg = &program.ctrs[t_ix];
+         cs_tprg = &this_program.ctrs[t_ix];
+         cs_all = &all.ctrs[t_ix];
+
+         if ((1 << t_ix) & gi_ptr->ctr_mask)
+           {
+             if (!cs_obj->runs++)
+               cs_obj->num = cs_tobj->num;
+             else if (cs_obj->num != cs_tobj->num)
+               goto read_mismatch;
+             cs_obj->sum_all += cs_tobj->sum_all;
+             if (cs_obj->run_max < cs_tobj->run_max)
+               cs_obj->run_max = cs_tobj->run_max;
+             cs_obj->sum_max += cs_tobj->run_max;
+
+             if (!cs_prg->runs++)
+               cs_prg->num = cs_tprg->num;
+             else if (cs_prg->num != cs_tprg->num)
+               goto read_mismatch;
+             cs_prg->sum_all += cs_tprg->sum_all;
+             if (cs_prg->run_max < cs_tprg->run_max)
+               cs_prg->run_max = cs_tprg->run_max;
+             cs_prg->sum_max += cs_tprg->run_max;
+           }
+         else if (cs_obj->num || cs_prg->num)
+           goto read_mismatch;
+
+         if (!cs_all->runs && cs_prg->runs)
+           memcpy (cs_all, cs_prg, sizeof (*cs_all));
+         else if (!all.checksum
+                  && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
+                  && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
+           {
+             fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
+                      gi_filename, GCOV_LOCKED
+                      ? "" : " or concurrent update without locking support");
+             all.checksum = ~0u;
+           }
+       }
+
+      c_ix = 0;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+       if ((1 << t_ix) & gi_ptr->ctr_mask)
+         {
+           values[c_ix] = gi_ptr->counts[c_ix].values;
+           c_ix++;
+         }
+
+      program.checksum = gcov_crc32;
+
+      /* Write out the data.  */
+      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
+      gcov_write_unsigned (gi_ptr->stamp);
+
+      /* Write execution counts for each function.  */
+      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+       {
+         fi_ptr = (const struct gcov_fn_info *)
+                 ((const char *) gi_ptr->functions + f_ix * fi_stride);
+
+         /* Announce function.  */
+         gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
+         gcov_write_unsigned (fi_ptr->ident);
+         gcov_write_unsigned (fi_ptr->lineno_checksum);
+         gcov_write_unsigned (fi_ptr->cfg_checksum);
+
+         c_ix = 0;
+         for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+           {
+             gcov_type *c_ptr;
+
+             if (!((1 << t_ix) & gi_ptr->ctr_mask))
+               continue;
+
+             n_counts = fi_ptr->n_ctrs[c_ix];
+
+             gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
+                                    GCOV_TAG_COUNTER_LENGTH (n_counts));
+             c_ptr = values[c_ix];
+             while (n_counts--)
+               gcov_write_counter (*c_ptr++);
+
+             values[c_ix] = c_ptr;
+             c_ix++;
+           }
+       }
+
+      /* Object file summary.  */
+      gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
+
+      /* Generate whole program statistics.  */
+      if (eof_pos)
+       gcov_seek (eof_pos);
+      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
+      if (!summary_pos)
+       gcov_write_unsigned (0);
+      if ((error = gcov_close ()))
+         fprintf (stderr, error  < 0 ?
+                  "profiling:%s:Overflow writing\n" :
+                  "profiling:%s:Error writing\n",
+                  gi_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 (gcov_version (info, info->version, 0))
+    {
+      const char *ptr = info->filename;
+      gcov_unsigned_t crc32 = gcov_crc32;
+      size_t filename_length =  strlen(info->filename);
+
+      /* Refresh the longest file name information */
+      if (filename_length > gcov_max_filename)
+        gcov_max_filename = filename_length;
+
+      do
+       {
+         unsigned ix;
+         gcov_unsigned_t value = *ptr << 24;
+
+         for (ix = 8; ix--; value <<= 1)
+           {
+             gcov_unsigned_t 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)
+{
+  const struct gcov_info *gi_ptr;
+
+  gcov_exit ();
+  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      unsigned t_ix;
+      const struct gcov_ctr_info *ci_ptr;
+
+      for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
+       if ((1 << t_ix) & gi_ptr->ctr_mask)
+         {
+           memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+           ci_ptr++;
+         }
+    }
+}
+
+#endif /* L_gcov */
+
+#ifdef L_gcov_merge_add
+/* The profile merging function that just adds the counters.  It is given
+   an array COUNTERS of N_COUNTERS old counters and it reads the same number
+   of counters from the gcov file.  */
+void
+__gcov_merge_add (gcov_type *counters, unsigned n_counters)
+{
+  for (; n_counters; counters++, n_counters--)
+    *counters += gcov_read_counter ();
+}
+#endif /* L_gcov_merge_add */
+
+#ifdef L_gcov_merge_ior
+/* The profile merging function that just adds the counters.  It is given
+   an array COUNTERS of N_COUNTERS old counters and it reads the same number
+   of counters from the gcov file.  */
+void
+__gcov_merge_ior (gcov_type *counters, unsigned n_counters)
+{
+  for (; n_counters; counters++, n_counters--)
+    *counters |= gcov_read_counter ();
+}
+#endif
+
+#ifdef L_gcov_merge_single
+/* The profile merging function for choosing the most common value.
+   It is given an array COUNTERS of N_COUNTERS old counters and it
+   reads the same number of counters from the gcov file.  The counters
+   are split into 3-tuples where the members of the tuple have
+   meanings:
+
+   -- the stored candidate on the most common value of the measured entity
+   -- counter
+   -- total number of evaluations of the value  */
+void
+__gcov_merge_single (gcov_type *counters, unsigned n_counters)
+{
+  unsigned i, n_measures;
+  gcov_type value, counter, all;
+
+  gcc_assert (!(n_counters % 3));
+  n_measures = n_counters / 3;
+  for (i = 0; i < n_measures; i++, counters += 3)
+    {
+      value = gcov_read_counter ();
+      counter = gcov_read_counter ();
+      all = gcov_read_counter ();
+
+      if (counters[0] == value)
+       counters[1] += counter;
+      else if (counter > counters[1])
+       {
+         counters[0] = value;
+         counters[1] = counter - counters[1];
+       }
+      else
+       counters[1] -= counter;
+      counters[2] += all;
+    }
+}
+#endif /* L_gcov_merge_single */
+
+#ifdef L_gcov_merge_delta
+/* The profile merging function for choosing the most common
+   difference between two consecutive evaluations of the value.  It is
+   given an array COUNTERS of N_COUNTERS old counters and it reads the
+   same number of counters from the gcov file.  The counters are split
+   into 4-tuples where the members of the tuple have meanings:
+
+   -- the last value of the measured entity
+   -- the stored candidate on the most common difference
+   -- counter
+   -- total number of evaluations of the value  */
+void
+__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
+{
+  unsigned i, n_measures;
+  gcov_type value, counter, all;
+
+  gcc_assert (!(n_counters % 4));
+  n_measures = n_counters / 4;
+  for (i = 0; i < n_measures; i++, counters += 4)
+    {
+      /* last = */ gcov_read_counter ();
+      value = gcov_read_counter ();
+      counter = gcov_read_counter ();
+      all = gcov_read_counter ();
+
+      if (counters[1] == value)
+       counters[2] += counter;
+      else if (counter > counters[2])
+       {
+         counters[1] = value;
+         counters[2] = counter - counters[2];
+       }
+      else
+       counters[2] -= counter;
+      counters[3] += all;
+    }
+}
+#endif /* L_gcov_merge_delta */
+
+#ifdef L_gcov_interval_profiler
+/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
+   corresponding counter in COUNTERS.  If the VALUE is above or below
+   the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
+   instead.  */
+
+void
+__gcov_interval_profiler (gcov_type *counters, gcov_type value,
+                         int start, unsigned steps)
+{
+  gcov_type delta = value - start;
+  if (delta < 0)
+    counters[steps + 1]++;
+  else if (delta >= steps)
+    counters[steps]++;
+  else
+    counters[delta]++;
+}
+#endif
+
+#ifdef L_gcov_pow2_profiler
+/* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
+   COUNTERS[0] is incremented.  */
+
+void
+__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
+{
+  if (value & (value - 1))
+    counters[0]++;
+  else
+    counters[1]++;
+}
+#endif
+
+/* Tries to determine the most common value among its inputs.  Checks if the
+   value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
+   is incremented.  If this is not the case and COUNTERS[1] is not zero,
+   COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
+   VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
+   function is called more than 50% of the time with one value, this value
+   will be in COUNTERS[0] in the end.
+
+   In any case, COUNTERS[2] is incremented.  */
+
+static inline void
+__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
+{
+  if (value == counters[0])
+    counters[1]++;
+  else if (counters[1] == 0)
+    {
+      counters[1] = 1;
+      counters[0] = value;
+    }
+  else
+    counters[1]--;
+  counters[2]++;
+}
+
+#ifdef L_gcov_one_value_profiler
+void
+__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
+{
+  __gcov_one_value_profiler_body (counters, value);
+}
+#endif
+
+#ifdef L_gcov_indirect_call_profiler
+
+/* By default, the C++ compiler will use function addresses in the
+   vtable entries.  Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
+   tells the compiler to use function descriptors instead.  The value
+   of this macro says how many words wide the descriptor is (normally 2),
+   but it may be dependent on target flags.  Since we do not have access
+   to the target flags here we just check to see if it is set and use
+   that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
+
+   It is assumed that the address of a function descriptor may be treated
+   as a pointer to a function.  */
+
+#ifdef TARGET_VTABLE_USES_DESCRIPTORS
+#define VTABLE_USES_DESCRIPTORS 1
+#else
+#define VTABLE_USES_DESCRIPTORS 0
+#endif
+
+/* Tries to determine the most common value among its inputs. */
+void
+__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
+                              void* cur_func, void* callee_func)
+{
+  /* If the C++ virtual tables contain function descriptors then one
+     function may have multiple descriptors and we need to dereference
+     the descriptors to see if they point to the same function.  */
+  if (cur_func == callee_func
+      || (VTABLE_USES_DESCRIPTORS && callee_func
+         && *(void **) cur_func == *(void **) callee_func))
+    __gcov_one_value_profiler_body (counter, value);
+}
+#endif
+
+
+#ifdef L_gcov_average_profiler
+/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
+   to saturate up.  */
+
+void
+__gcov_average_profiler (gcov_type *counters, gcov_type value)
+{
+  counters[0] += value;
+  counters[1] ++;
+}
+#endif
+
+#ifdef L_gcov_ior_profiler
+/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
+   to saturate up.  */
+
+void
+__gcov_ior_profiler (gcov_type *counters, gcov_type value)
+{
+  *counters |= value;
+}
+#endif
+
+#ifdef L_gcov_fork
+/* A wrapper for the fork function.  Flushes the accumulated profiling data, so
+   that they are not counted twice.  */
+
+pid_t
+__gcov_fork (void)
+{
+  __gcov_flush ();
+  return fork ();
+}
+#endif
+
+#ifdef L_gcov_execl
+/* A wrapper for the execl function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execl (const char *path, char *arg, ...)
+{
+  va_list ap, aq;
+  unsigned i, length;
+  char **args;
+
+  __gcov_flush ();
+
+  va_start (ap, arg);
+  va_copy (aq, ap);
+
+  length = 2;
+  while (va_arg (ap, char *))
+    length++;
+  va_end (ap);
+
+  args = (char **) alloca (length * sizeof (void *));
+  args[0] = arg;
+  for (i = 1; i < length; i++)
+    args[i] = va_arg (aq, char *);
+  va_end (aq);
+
+  return execv (path, args);
+}
+#endif
+
+#ifdef L_gcov_execlp
+/* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execlp (const char *path, char *arg, ...)
+{
+  va_list ap, aq;
+  unsigned i, length;
+  char **args;
+
+  __gcov_flush ();
+
+  va_start (ap, arg);
+  va_copy (aq, ap);
+
+  length = 2;
+  while (va_arg (ap, char *))
+    length++;
+  va_end (ap);
+
+  args = (char **) alloca (length * sizeof (void *));
+  args[0] = arg;
+  for (i = 1; i < length; i++)
+    args[i] = va_arg (aq, char *);
+  va_end (aq);
+
+  return execvp (path, args);
+}
+#endif
+
+#ifdef L_gcov_execle
+/* A wrapper for the execle function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execle (const char *path, char *arg, ...)
+{
+  va_list ap, aq;
+  unsigned i, length;
+  char **args;
+  char **envp;
+
+  __gcov_flush ();
+
+  va_start (ap, arg);
+  va_copy (aq, ap);
+
+  length = 2;
+  while (va_arg (ap, char *))
+    length++;
+  va_end (ap);
+
+  args = (char **) alloca (length * sizeof (void *));
+  args[0] = arg;
+  for (i = 1; i < length; i++)
+    args[i] = va_arg (aq, char *);
+  envp = va_arg (aq, char **);
+  va_end (aq);
+
+  return execve (path, args, envp);
+}
+#endif
+
+#ifdef L_gcov_execv
+/* A wrapper for the execv function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execv (const char *path, char *const argv[])
+{
+  __gcov_flush ();
+  return execv (path, argv);
+}
+#endif
+
+#ifdef L_gcov_execvp
+/* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execvp (const char *path, char *const argv[])
+{
+  __gcov_flush ();
+  return execvp (path, argv);
+}
+#endif
+
+#ifdef L_gcov_execve
+/* A wrapper for the execve function.  Flushes the accumulated profiling data, so
+   that they are not lost.  */
+
+int
+__gcov_execve (const char *path, char *const argv[], char *const envp[])
+{
+  __gcov_flush ();
+  return execve (path, argv, envp);
+}
+#endif
+#endif /* inhibit_libc */