diff mbox

[google,gcc-4_8] backport libgcov re-factoring patches from trunk

Message ID CAF1bQ=RymDah=o26s=uP8=hP+6HyJkRGeQ4y7e4S20YiJhZgSQ@mail.gmail.com
State New
Headers show

Commit Message

Rong Xu Jan. 15, 2014, 10:58 p.m. UTC
attached is the updated patch.

On Wed, Jan 15, 2014 at 10:51 AM, Rong Xu <xur@google.com> wrote:
> On Wed, Jan 15, 2014 at 10:40 AM, Xinliang David Li <davidxl@google.com> wrote:
>> In libgcov-driver.c,
>>
>> 1) there are couple of places with trailing white spaces (e.g, in
>> gcov_sort_n_vals body), please remove
> They are from the existing code. But I'll fix them.
>
>> 2) gcov_exit_write_gcda in trunk takes eof_pos as an arg, and check it
>> before writing the header. I think this is more correct than in your
>> patch
> That's true. But this logic is from the newer code in trunk.
> Current 4_8 code does not check this. I deliberately did this because I thought
> the backporting patch should not change this.
>
> I'll change to the trunk verison then.
>
>
>> 3) It would be better to keep the function order the same in trunk
>> (e.g, compute summary related, merge gcda and write gcda etc); it is
>> also helpful to keep LIPO related functions order in the same way as
>> in google/main so that a better diff can be done
>> 4) libdriver-profiler.c -- make the function ordering the same as in
>> google/main would be helpful.
>
> sure. I'll do this two items. Will send an updated patch soon.
>
>>
>> thanks,
>>
>> David
>>
>> On Wed, Jan 15, 2014 at 10:03 AM, Rong Xu <xur@google.com> wrote:
>>> The attached patch backports libgcov re-factoring patches from trunk.
>>>
>>> Tested with google internal benchmarks, SPEC2006, bootstrap and
>>> profiledbootstrap.
>>>
>>> OK for google/gcc-4_8 branch?
>>>
>>> -Rong

Comments

Xinliang David Li Jan. 15, 2014, 11:55 p.m. UTC | #1
ok for google branch.

David

On Wed, Jan 15, 2014 at 2:58 PM, Rong Xu <xur@google.com> wrote:
> attached is the updated patch.
>
> On Wed, Jan 15, 2014 at 10:51 AM, Rong Xu <xur@google.com> wrote:
>> On Wed, Jan 15, 2014 at 10:40 AM, Xinliang David Li <davidxl@google.com> wrote:
>>> In libgcov-driver.c,
>>>
>>> 1) there are couple of places with trailing white spaces (e.g, in
>>> gcov_sort_n_vals body), please remove
>> They are from the existing code. But I'll fix them.
>>
>>> 2) gcov_exit_write_gcda in trunk takes eof_pos as an arg, and check it
>>> before writing the header. I think this is more correct than in your
>>> patch
>> That's true. But this logic is from the newer code in trunk.
>> Current 4_8 code does not check this. I deliberately did this because I thought
>> the backporting patch should not change this.
>>
>> I'll change to the trunk verison then.
>>
>>
>>> 3) It would be better to keep the function order the same in trunk
>>> (e.g, compute summary related, merge gcda and write gcda etc); it is
>>> also helpful to keep LIPO related functions order in the same way as
>>> in google/main so that a better diff can be done
>>> 4) libdriver-profiler.c -- make the function ordering the same as in
>>> google/main would be helpful.
>>
>> sure. I'll do this two items. Will send an updated patch soon.
>>
>>>
>>> thanks,
>>>
>>> David
>>>
>>> On Wed, Jan 15, 2014 at 10:03 AM, Rong Xu <xur@google.com> wrote:
>>>> The attached patch backports libgcov re-factoring patches from trunk.
>>>>
>>>> Tested with google internal benchmarks, SPEC2006, bootstrap and
>>>> profiledbootstrap.
>>>>
>>>> OK for google/gcc-4_8 branch?
>>>>
>>>> -Rong
diff mbox

Patch

Index: libgcc/libgcov-interface.c
===================================================================
--- libgcc/libgcov-interface.c	(revision 0)
+++ libgcc/libgcov-interface.c	(revision 0)
@@ -0,0 +1,310 @@ 
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2013 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 "libgcov.h"
+#include "gthr.h"
+
+#if defined(inhibit_libc)
+/* If libc and its header files are not available, provide dummy functions.  */
+
+#ifdef L_gcov_flush
+void __gcov_flush (void) {}
+#endif
+
+#ifdef L_gcov_reset
+void __gcov_reset (void) {}
+#endif
+
+#ifdef L_gcov_dump
+void __gcov_dump (void) {}
+#endif
+
+#else
+
+extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
+extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
+extern void set_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
+extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
+
+#ifdef L_gcov_flush
+
+#ifdef __GTHREAD_MUTEX_INIT
+ATTRIBUTE_HIDDEN __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
+#define init_mx_once()
+#else
+__gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
+
+static void
+init_mx (void)
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
+}
+static void
+init_mx_once (void)
+{
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  __gthread_once (&once, init_mx);
+}
+#endif
+
+/* 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)
+{
+  init_mx_once ();
+  __gthread_mutex_lock (&__gcov_flush_mx);
+
+  gcov_exit ();
+  gcov_clear ();
+
+  __gthread_mutex_unlock (&__gcov_flush_mx);
+}
+
+#endif /* L_gcov_flush */
+
+#ifdef L_gcov_reset
+
+/* Function that can be called from application to reset counters to zero,
+   in order to collect profile in region of interest.  */
+
+void
+__gcov_reset (void)
+{
+  gcov_clear ();
+  /* Re-enable dumping to support collecting profile in multiple regions
+     of interest.  */
+  reset_gcov_dump_complete ();
+}
+
+#endif /* L_gcov_reset */
+
+#ifdef L_gcov_dump
+
+/* Function that can be called from application to write profile collected
+   so far, in order to collect profile in region of interest.  */
+
+void
+__gcov_dump (void)
+{
+  gcov_exit ();
+  /* Prevent profile from being dumped a second time on application exit.  */
+  set_gcov_dump_complete ();
+}
+
+#endif /* L_gcov_dump */
+
+#ifdef L_gcov_sampling
+
+/* Emitted in coverage.c.  */
+
+/* Sampling period.  */
+extern gcov_unsigned_t __gcov_sampling_period;
+extern gcov_unsigned_t __gcov_has_sampling;
+void __gcov_set_sampling_period (unsigned int period);
+unsigned int __gcov_sampling_enabled (void);
+/* Per thread sample counter.  */
+THREAD_PREFIX gcov_unsigned_t __gcov_sample_counter = 0;
+
+/* Set sampling period to PERIOD.  */
+
+void __gcov_set_sampling_period (unsigned int period)
+{
+  gcc_assert (__gcov_has_sampling);
+  __gcov_sampling_period = period;
+}
+
+unsigned int __gcov_sampling_enabled (void)
+{
+  return __gcov_has_sampling;
+}
+
+#endif
+
+#ifdef L_gcov_prefix
+
+char *__gcov_get_profile_prefix (void);
+
+/* Profile directory prefix specified to -fprofile-generate=.  */
+extern char * __gcov_profile_prefix;
+
+char *__gcov_get_profile_prefix (void)
+{
+  return __gcov_profile_prefix;
+}
+
+#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)
+{
+  pid_t pid;
+  extern __gthread_mutex_t __gcov_flush_mx;
+  __gcov_flush ();
+  pid = fork ();
+  if (pid == 0)
+    __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
+  return pid;
+}
+#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: libgcc/libgcov.c
===================================================================
--- libgcc/libgcov.c	(revision 206637)
+++ libgcc/libgcov.c	(working copy)
@@ -1,1989 +0,0 @@ 
-/* Routines required for instrumenting a program.  */
-/* Compile this one with gcc.  */
-/* Copyright (C) 1989-2013 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"
-#include "libgcc_tm.h"
-#include "gthr.h"
-
-#if 1
-#define THREAD_PREFIX __thread
-#else
-#define THREAD_PREFIX
-#endif
-
-#if defined(inhibit_libc)
-#define IN_LIBGCOV (-1)
-#else
-#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_reset
-void __gcov_reset (void) {}
-#endif
-
-#ifdef L_gcov_dump
-void __gcov_dump (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
-
-extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
-extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
-extern int gcov_dump_complete ATTRIBUTE_HIDDEN;
-
-#ifdef L_gcov
-#include "gcov-io.c"
-
-/* Create a strong reference to these symbols so that they are
-   unconditionally pulled into the instrumented binary, even when
-   the only reference is a weak reference. This is necessary because
-   we are using weak references to handle older compilers that
-   pre-date these new functions. A subtlety of the linker is that
-   it will only resolve weak references defined within archive libraries
-   when there is a string reference to something else defined within
-   the same object file. Since these two functions are defined within
-   their own object files (using L_gcov_reset and L_gcov_dump), they
-   would not get resolved. Since there are symbols within the main L_gcov
-   section that are strongly referenced during -fprofile-generate builds,
-   these symbols will always need to be resolved.  */
-void (*__gcov_dummy_ref1)() = &__gcov_reset;
-void (*__gcov_dummy_ref2)() = &__gcov_dump;
-
-
-/* Default callback function for profile instrumentation callback.  */
-__attribute__((weak)) void
-__coverage_callback (gcov_type funcdef_no __attribute__ ((unused)),
-                     int edge_no __attribute__ ((unused)))
-{
-   /* nothing */
-}
-
-
-/* Utility function for outputing errors.  */
-static int
-gcov_error (const char *fmt, ...)
-{
-  int ret;
-  va_list argp;
-  va_start (argp, fmt);
-  ret = vfprintf (stderr, fmt, argp);
-  va_end (argp);
-  return ret;
-}
-
-/* Emitted in coverage.c.  */
-
-/* Sampling period.  */
-extern gcov_unsigned_t __gcov_sampling_period;
-extern gcov_unsigned_t __gcov_has_sampling;
-static int gcov_sampling_period_initialized = 0;
-void __gcov_set_sampling_period (unsigned int period);
-unsigned int __gcov_sampling_enabled ();
-
-/* Set sampling period to PERIOD.  */
-
-void __gcov_set_sampling_period (unsigned int period)
-{
-  gcc_assert (__gcov_has_sampling);
-  __gcov_sampling_period = period;
-}
-
-unsigned int __gcov_sampling_enabled ()
-{
-  return __gcov_has_sampling;
-}
-
-/* Profile directory prefix specified to -fprofile-generate=.  */
-extern char * __gcov_profile_prefix;
-
-char *__gcov_get_profile_prefix ()
-{
-  return __gcov_profile_prefix;
-}
-
-/* Per thread sample counter.  */
-THREAD_PREFIX gcov_unsigned_t __gcov_sample_counter = 0;
-
-struct gcov_summary_buffer
-{
-  struct gcov_summary_buffer *next;
-  struct gcov_summary summary;
-};
-
-static struct gcov_summary_buffer *next_sum_buffer, *sum_buffer;
-static struct gcov_summary_buffer **sum_tail;
-
-/* Chain of per-object gcov structures.  */
-extern 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;
-
-/* Unique identifier assigned to each module (object file).  */
-static gcov_unsigned_t gcov_cur_module_id = 0;
-
-/* Pointer to the direct-call counters (per call-site counters).
-   Initialized by the caller.  */
-THREAD_PREFIX gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN;
-
-/* Direct call callee address.  */
-THREAD_PREFIX void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN;
-
-/* Pointer to the indirect-call counters (per call-site counters).
-   Initialized by the caller.  */
-THREAD_PREFIX gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
-
-/* Indirect call callee address.  */
-THREAD_PREFIX void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
-
-/* Dynamic call graph build and form module groups.  */
-void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
-void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
-
-/* Profile summary for the gdca file, used in sanity check?  */
-static struct gcov_summary all;
-
-/* Profile summary for this program in current exeuction.  */
-static struct gcov_summary this_program;
-
-/* Merged profile summary for this program.  */
-static struct gcov_summary program;
-
-/* Record the position of summary info.  */
-static gcov_position_t summary_pos = 0;
-
-/* Record the postion of eof.  */
-static gcov_position_t eof_pos = 0;
-
-/* Number of chars in prefix to be stripped.  */
-static int gcov_prefix_strip = 0;
-
-/* The length of path prefix.  */
-static size_t prefix_length = 0;
-
-/* gi_filename is current object filename.
-   gi_filename_up points to the stripped filename.  */
-static char *gi_filename, *gi_filename_up;
-
-static int gcov_open_by_filename (char * gi_filename);
-static int gcov_exit_init (void);
-static void gcov_dump_one_gcov (struct gcov_info *gi_ptr);
-
-/* Flag when the profile has already been dumped via __gcov_dump().  */
-int gcov_dump_complete = 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
-}
-
-/* Open a file with the specified name.  */
-
-static int
-gcov_open_by_filename (char * gi_filename)
-{
-  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))
-        {
-          gcov_error ("profiling:%s:Skip\n", gi_filename);
-          return -1;
-        }
-      if (!gcov_open (gi_filename))
-        {
-          gcov_error ("profiling:%s:Cannot open\n", gi_filename);
-          return -1;
-        }
-    }
-  return 0;
-}
-
-
-/* Determine whether a counter is active.  */
-
-static inline int
-gcov_counter_active (const struct gcov_info *info, unsigned int type)
-{
-  return (info->merge[type] != 0);
-}
-
-
-/* Add an unsigned value to the current crc */
-
-static gcov_unsigned_t
-crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
-{
-  unsigned ix;
-
-  for (ix = 32; ix--; value <<= 1)
-    {
-      unsigned feedback;
-
-      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
-      crc32 <<= 1;
-      crc32 ^= feedback;
-    }
-
-  return crc32;
-}
-
-/* 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 __attribute__ ((unused)), 
-              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);
-
-      if (filename)
-        gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-                   filename, e, v);
-      else
-        gcov_error ("profiling:Version mismatch - expected %.4s got %.4s\n", e, v);
-      return 0;
-    }
-  return 1;
-}
-
-#define GCOV_GET_FILENAME gcov_strip_leading_dirs
-
-/* Insert counter VALUE into HISTOGRAM.  */
-
-static void
-gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
-{
-  unsigned i;
-
-  i = gcov_histo_index(value);
-  histogram[i].num_counters++;
-  histogram[i].cum_value += value;
-  if (value < histogram[i].min_value)
-    histogram[i].min_value = value;
-}
-
-/* Computes a histogram of the arc counters to place in the summary SUM.  */
-
-static void
-gcov_compute_histogram (struct gcov_summary *sum)
-{
-  struct gcov_info *gi_ptr;
-  const struct gcov_fn_info *gfi_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-  struct gcov_ctr_summary *cs_ptr;
-  unsigned t_ix, f_ix, ctr_info_ix, ix;
-  int h_ix;
-
-  /* This currently only applies to arc counters.  */
-  t_ix = GCOV_COUNTER_ARCS;
-
-  /* First check if there are any counts recorded for this counter.  */
-  cs_ptr = &(sum->ctrs[t_ix]);
-  if (!cs_ptr->num)
-    return;
-
-  for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
-    {
-      cs_ptr->histogram[h_ix].num_counters = 0;
-      cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max;
-      cs_ptr->histogram[h_ix].cum_value = 0;
-    }
-
-  /* Walk through all the per-object structures and record each of
-     the count values in histogram.  */
-  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      if (!gi_ptr->merge[t_ix])
-        continue;
-
-      /* Find the appropriate index into the gcov_ctr_info array
-         for the counter we are currently working on based on the
-         existence of the merge function pointer for this object.  */
-      for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++)
-        {
-          if (gi_ptr->merge[ix])
-            ctr_info_ix++;
-        }
-      for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
-        {
-          gfi_ptr = gi_ptr->functions[f_ix];
-
-          if (!gfi_ptr || gfi_ptr->key != gi_ptr)
-            continue;
-
-          ci_ptr = &gfi_ptr->ctrs[ctr_info_ix];
-          for (ix = 0; ix < ci_ptr->num; ix++)
-            gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]);
-        }
-    }
-}
-
-/* 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.  */
-
-/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
-   put the result into GI_FILENAME_UP.  */
-
-static void
-gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip,
-			 const char *filename, char *gi_filename_up)
-{
-  /* Avoid to add multiple drive letters into combined path.  */
-  if (prefix_length != 0 && HAS_DRIVE_SPEC(filename))
-    filename += 2;
-
-  /* Build relocated filename, stripping off leading
-     directories from the initial filename if requested. */
-  if (gcov_prefix_strip > 0)
-    {
-      int level = 0;
-      const char *s = filename;
-      if (IS_DIR_SEPARATOR(*s))
-	++s;
-
-      /* Skip selected directory levels. */
-      for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
-        if (IS_DIR_SEPARATOR(*s))
-          {
-            filename = s;
-            level++;
-          }
-    }
-
-  /* Update complete filename with stripped original. */
-  if (prefix_length != 0 && !IS_DIR_SEPARATOR (*filename))
-    {
-      /* If prefix is given, add directory separator.  */
-      strcpy (gi_filename_up, "/");
-      strcpy (gi_filename_up + 1, filename);
-    }
-  else
-    strcpy (gi_filename_up, filename);
-}
-
-/* This function allocates the space to store current file name.  */
-
-static void
-gcov_alloc_filename (void)
-{
-  /* Get file name relocation prefix.  Non-absolute values are ignored.  */
-  const char *gcov_prefix = 0;
-
-  prefix_length = 0;
-  gcov_prefix_strip = 0;
-
-  {
-    /* 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.  */
-  gi_filename = (char *) malloc (prefix_length + gcov_max_filename + 2);
-  if (prefix_length)
-    memcpy (gi_filename, gcov_prefix, prefix_length);
-
-  gi_filename_up = gi_filename + prefix_length;
-}
-
-/* Sort N entries in VALUE_ARRAY in descending order.
-   Each entry in VALUE_ARRAY has two values. The sorting
-   is based on the second value.  */
-
-GCOV_LINKAGE  void
-gcov_sort_n_vals (gcov_type *value_array, int n)
-{
-  int j, k;
-  for (j = 2; j < n; j += 2)
-    {
-      gcov_type cur_ent[2];
-      cur_ent[0] = value_array[j];
-      cur_ent[1] = value_array[j + 1];
-      k = j - 2;
-      while (k >= 0 && value_array[k + 1] < cur_ent[1])
-        {
-          value_array[k + 2] = value_array[k];
-          value_array[k + 3] = value_array[k+1];
-          k -= 2;
-        }
-      value_array[k + 2] = cur_ent[0];
-      value_array[k + 3] = cur_ent[1];
-    }
-}
-
-/* Sort the profile counters for all indirect call sites. Counters
-   for each call site are allocated in array COUNTERS.  */
-
-static void
-gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
-{
-  int i;
-  gcov_type *values;
-  int n = counters->num;
-  gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
-
-  values = counters->values;
-
-  for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
-    {
-      gcov_type *value_array = &values[i + 1];
-      gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
-    }
-}
-
-/* Write imported files (auxiliary modules) for primary module GI_PTR
-   into file GI_FILENAME.  */
-
-static void
-gcov_write_import_file (char *gi_filename, struct gcov_info *gi_ptr)
-{
-  char  *gi_imports_filename;
-  const char *gcov_suffix;
-  FILE *imports_file;
-  size_t prefix_length, suffix_length;
-
-  gcov_suffix = getenv ("GCOV_IMPORTS_SUFFIX");
-  if (!gcov_suffix || !strlen (gcov_suffix))
-    gcov_suffix = ".imports";
-  suffix_length = strlen (gcov_suffix);
-  prefix_length = strlen (gi_filename);
-  gi_imports_filename = (char *) alloca (prefix_length + suffix_length + 1);
-  memset (gi_imports_filename, 0, prefix_length + suffix_length + 1);
-  memcpy (gi_imports_filename, gi_filename, prefix_length);
-  memcpy (gi_imports_filename + prefix_length, gcov_suffix, suffix_length);
-  imports_file = fopen (gi_imports_filename, "w");
-  if (imports_file)
-    {
-      const struct dyn_imp_mod **imp_mods;
-      unsigned i, imp_len;
-      imp_mods = gcov_get_sorted_import_module_array (gi_ptr, &imp_len);
-      if (imp_mods)
-        {
-          for (i = 0; i < imp_len; i++)
-	    {
-	      fprintf (imports_file, "%s\n",
-		       imp_mods[i]->imp_mod->mod_info->source_filename);
-	      fprintf (imports_file, "%s%s\n",
-		       imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX);
-	    }
-          free (imp_mods);
-        }
-      fclose (imports_file);
-    }
-}
-
-static void
-gcov_dump_module_info (void)
-{
-  struct gcov_info *gi_ptr;
-
-  __gcov_compute_module_groups ();
-
-  /* Now write out module group info.  */
-  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-  {
-    int error;
-
-    GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename,
-                       gi_filename_up);
-    error = gcov_open_by_filename (gi_filename);
-    if (error != 0)
-      continue;
-
-    /* Overwrite the zero word at the of the file.  */
-    gcov_rewrite ();
-    gcov_seek (gi_ptr->eof_pos);
-
-    gcov_write_module_infos (gi_ptr);
-    /* Write the end marker  */
-    gcov_write_unsigned (0);
-    gcov_truncate ();
-
-    if ((error = gcov_close ()))
-         gcov_error (error  < 0 ?  "profiling:%s:Overflow writing\n" :
-                                   "profiling:%s:Error writing\n",
-                                   gi_filename);
-    gcov_write_import_file (gi_filename, gi_ptr);
-  }
-  __gcov_finalize_dyn_callgraph ();
-}
-
-/* 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.  */
-
-void
-gcov_exit (void)
-{
-  struct gcov_info *gi_ptr;
-  int dump_module_info;
-
-  /* Prevent the counters from being dumped a second time on exit when the
-     application already wrote out the profile using __gcov_dump().  */
-  if (gcov_dump_complete)
-    return;
-
-  dump_module_info = gcov_exit_init ();
-
-  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    gcov_dump_one_gcov (gi_ptr);
-
-  if (dump_module_info)
-    gcov_dump_module_info ();
-
-  free (gi_filename);
-}
-
-/* Reset all counters to zero.  */
-
-void
-gcov_clear (void)
-{
-  const struct gcov_info *gi_ptr;
-
-  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      unsigned f_ix;
-
-      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-	{
-	  unsigned t_ix;
-	  const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
-
-	  if (!gfi_ptr || gfi_ptr->key != gi_ptr)
-	    continue;
-	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
-	  for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
-	    {
-	      if (!gi_ptr->merge[t_ix])
-		continue;
-	      
-	      memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
-	      ci_ptr++;
-	    }
-	}
-    }
-}
-
-/* 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 (!gcov_sampling_period_initialized)
-    {
-      const char* env_value_str = getenv ("GCOV_SAMPLING_PERIOD");
-      if (env_value_str)
-        {
-          int env_value_int = atoi(env_value_str);
-          if (env_value_int >= 1)
-            __gcov_sampling_period = env_value_int;
-        }
-      gcov_sampling_period_initialized = 1;
-    }
-
-  if (!info->version || !info->n_functions)
-    return;
-
-  if (gcov_version (info, info->version, 0))
-    {
-      const char *ptr = info->filename;
-      size_t filename_length = strlen (info->filename);
-
-      /* Refresh the longest file name information.  */
-      if (filename_length > gcov_max_filename)
-        gcov_max_filename = filename_length;
-
-      /* Assign the module ID (starting at 1).  */
-      info->mod_info->ident = (++gcov_cur_module_id);
-      gcc_assert (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (GEN_FUNC_GLOBAL_ID (
-                                                       info->mod_info->ident, 0))
-                  == info->mod_info->ident);
-
-      if (!__gcov_list)
-        {
-          atexit (gcov_exit);
-        }
-
-      info->next = __gcov_list;
-      __gcov_list = info;
-    }
-  info->version = 0;
-}
-
-#ifdef __GTHREAD_MUTEX_INIT
-ATTRIBUTE_HIDDEN __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
-#define init_mx_once()
-#else
-__gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
-
-static void
-init_mx (void)
-{
-  __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
-}
-static void
-init_mx_once (void)
-{
-  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
-  __gthread_once (&once, init_mx);
-}
-#endif
-
-/* 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)
-{
-  init_mx_once ();
-  __gthread_mutex_lock (&__gcov_flush_mx);
-
-  gcov_exit ();
-  gcov_clear ();
-
-  __gthread_mutex_unlock (&__gcov_flush_mx);
-}
-
-static void
-gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
-{
-  unsigned int i;
-  int f_ix;
-  const struct gcov_fn_info *gfi_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-
-  for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
-    {
-      gfi_ptr = gi_ptr->functions[f_ix];
-      ci_ptr = gfi_ptr->ctrs;
-      for (i = 0; i < GCOV_COUNTERS; i++)
-        {
-          if (!gcov_counter_active (gi_ptr, i))
-            continue;
-          if (i == GCOV_COUNTER_ICALL_TOPNV)
-            {
-              gcov_sort_icall_topn_counter (ci_ptr);
-              break;
-            }
-          ci_ptr++;
-        }
-     }
-}
-
-/* Compute object summary recored in gcov_info INFO. The result is
-   stored in OBJ_SUM. Note that the caller is responsible for
-   zeroing out OBJ_SUM, otherwise the summary is accumulated.  */
-
-static void
-gcov_object_summary (struct gcov_info *info, struct gcov_summary *obj_sum)
-{
-  const struct gcov_fn_info *gfi_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-  struct gcov_ctr_summary *cs_ptr;
-  gcov_unsigned_t c_num;
-  unsigned t_ix;
-  int f_ix;
-  gcov_unsigned_t crc32 = gcov_crc32;
-
-  /* Totals for this object file.  */
-  crc32 = crc32_unsigned (crc32, info->stamp);
-  crc32 = crc32_unsigned (crc32, info->n_functions);
-
-  for (f_ix = 0; (unsigned) f_ix != info->n_functions; f_ix++)
-    {
-      gfi_ptr = info->functions[f_ix];
-
-      if (!gfi_ptr || gfi_ptr->key != info)
-        gfi_ptr = 0;
-
-      crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
-      crc32 = crc32_unsigned (crc32,
-                              gfi_ptr ? gfi_ptr->lineno_checksum : 0);
-
-      if (!gfi_ptr)
-        continue;
-
-      ci_ptr = gfi_ptr->ctrs;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
-        {
-          if (!info->merge[t_ix])
-            continue;
-
-          cs_ptr = &(obj_sum->ctrs[t_ix]);
-          cs_ptr->num += ci_ptr->num;
-          crc32 = crc32_unsigned (crc32, 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++;
-        }
-    }
-  gcov_crc32 = crc32;
-}
-
-/* Merge with existing gcda file in the same directory to avoid
-   excessive growthe of the files.  */
-
-static int
-gcov_merge_gcda_file (struct gcov_info *gi_ptr)
-{
-  struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
-  unsigned t_ix, f_ix = 0;
-
-  const struct gcov_fn_info *gfi_ptr;
-  int error = 0;
-  gcov_unsigned_t tag, length, version, stamp;
-
-  eof_pos = 0;
-  summary_pos = 0;
-  sum_buffer = 0;
-  sum_tail = &sum_buffer;
-
-  tag = gcov_read_unsigned ();
-  if (tag)
-    {
-      /* Merge data from file.  */
-      if (tag != GCOV_DATA_MAGIC)
-        {
-          gcov_error ("profiling:%s:Not a gcov data file\n", gi_filename);
-          goto read_fatal;
-        }
-     version = gcov_read_unsigned ();
-     if (!gcov_version (gi_ptr, version, gi_filename))
-       goto read_fatal;
-
-     stamp = gcov_read_unsigned ();
-     if (stamp != gi_ptr->stamp)
-       /* Read from a different compilation. Overwrite the file.  */
-       goto rewrite;
-
-      /* Look for program summary.  */
-     for (f_ix = ~0u;;)
-       {
-         struct gcov_summary tmp;
-
-         eof_pos = gcov_position ();
-         tag = gcov_read_unsigned ();
-         if (tag != GCOV_TAG_PROGRAM_SUMMARY)
-           break;
-
-         length = gcov_read_unsigned ();
-         gcov_read_summary (&tmp);
-         if ((error = gcov_is_error ()))
-           goto read_error;
-         if (summary_pos)
-             {
-               /* Save all summaries after the one that will be
-                  merged into below. These will need to be rewritten
-                  as histogram merging may change the number of non-zero
-                  histogram entries that will be emitted, and thus the
-                  size of the merged summary.  */
-               (*sum_tail) = (struct gcov_summary_buffer *)
-                   malloc (sizeof(struct gcov_summary_buffer));
-               (*sum_tail)->summary = tmp;
-               (*sum_tail)->next = 0;
-               sum_tail = &((*sum_tail)->next);
-               goto next_summary;
-             }
-           if (tmp.checksum != gcov_crc32)
-             goto next_summary;
-
-           for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
-             if (tmp.ctrs[t_ix].num != this_program.ctrs[t_ix].num)
-               goto next_summary;
-           program = tmp;
-           summary_pos = eof_pos;
-
-         next_summary:;
-         }
-
-     /* Merge execution counts for each function.  */
-     for (f_ix = 0; f_ix != gi_ptr->n_functions;
-          f_ix++, tag = gcov_read_unsigned ())
-       {
-         const struct gcov_ctr_info *ci_ptr;
-
-         gfi_ptr = gi_ptr->functions[f_ix];
-
-         if (tag != GCOV_TAG_FUNCTION)
-           goto read_mismatch;
-         length = gcov_read_unsigned ();
-
-         if (!length)
-           /* This function did not appear in the other program.
-              We have nothing to merge.  */
-           continue;
-
-         /* Check function.  */
-         if (length != GCOV_TAG_FUNCTION_LENGTH)
-           goto read_mismatch;
-
-         gcc_assert (gfi_ptr && gfi_ptr->key == gi_ptr);
-
-         if (gcov_read_unsigned () != gfi_ptr->ident
-             || gcov_read_unsigned () != gfi_ptr->lineno_checksum
-             || gcov_read_unsigned () != gfi_ptr->cfg_checksum)
-            goto read_mismatch;
-
-         ci_ptr = gfi_ptr->ctrs;
-         for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-           {
-             gcov_merge_fn merge = gi_ptr->merge[t_ix];
-
-             if (!merge)
-               continue;
-
-             tag = gcov_read_unsigned ();
-             length = gcov_read_unsigned ();
-             if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
-                 || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
-               goto read_mismatch;
-             (*merge) (ci_ptr->values, ci_ptr->num);
-             ci_ptr++;
-           }
-           if ((error = gcov_is_error ()))
-             goto read_error;
-       }
-     if (tag && tag != GCOV_TAG_MODULE_INFO)
-       goto read_mismatch;
-    }
-  goto rewrite;
-
-read_error:;
-    gcov_error (error < 0 ? "profiling:%s:Overflow merging\n"
-                : "profiling:%s:Error merging\n", gi_filename);
-    goto read_fatal;
-
-    goto rewrite;
-
-read_mismatch:;
-    gcov_error ("profiling:%s:Merge mismatch for %s\n",
-                 gi_filename, f_ix + 1 ? "function" : "summaries");
-    goto read_fatal;
-
-read_fatal:;
-    gcov_close ();
-    return 1;
-
-rewrite:;
-    gcov_rewrite ();
-    if (!summary_pos)
-      {
-        memset (&program, 0, sizeof (program));
-        summary_pos = eof_pos;
-      }
-
-    /* Merge the summaries.  */
-    for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
-      {
-        cs_prg = &program.ctrs[t_ix];
-        cs_tprg = &this_program.ctrs[t_ix];
-        cs_all = &all.ctrs[t_ix];
-
-        if (gi_ptr->merge[t_ix])
-          {
-            if (!cs_prg->runs++)
-              cs_prg->num = cs_tprg->num;
-            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;
-            if (cs_prg->runs == 1)
-              memcpy (cs_prg->histogram, cs_tprg->histogram,
-                      sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
-            else
-              gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram);
-          }
-        else if (cs_prg->runs)
-          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)
-                 /* Don't compare the histograms, which may have slight
-                     variations depending on the order they were updated
-                     due to the truncating integer divides used in the
-                     merge.  */
-                  && memcmp (cs_all, cs_prg,
-                             sizeof (*cs_all) - (sizeof (gcov_bucket_type)
-                                                 * GCOV_HISTOGRAM_SIZE)))
-          {
-            gcov_error ("profiling:%s:Invocation mismatch - "
-                "some data files may have been removed%s\n",
-            gi_filename, GCOV_LOCKED
-            ? "" : " or concurrent update without locking support");
-            all.checksum = ~0u;
-          }
-      }
-
-  program.checksum = gcov_crc32;
-
-  return 0;
-}
-
-/* This function returns the size of gcda file to be written. Note
-   the size is in units of gcov_type.  */
-
-GCOV_LINKAGE unsigned
-gcov_gcda_file_size (struct gcov_info *gi_ptr)
-{
-  unsigned size;
-  const struct gcov_fn_info *fi_ptr;
-  unsigned f_ix, t_ix, h_ix, h_cnt = 0;
-  unsigned n_counts;
-  const struct gcov_ctr_info *ci_ptr;
-  struct gcov_summary *sum = &this_program;
-  const struct gcov_ctr_summary *csum;
-
-  /* GCOV_DATA_MAGIC, GCOV_VERSION and time_stamp.  */
-  size = 3;
-
-  /* Program summary, which depends on the number of non-zero
-      histogram entries.  */
-   csum = &sum->ctrs[GCOV_COUNTER_ARCS];
-   for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
-     {
-       if (csum->histogram[h_ix].num_counters > 0)
-         h_cnt++;
-     }
-   size += 2 + GCOV_TAG_SUMMARY_LENGTH(h_cnt);
-
-  /* size for each function.  */
-  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-    {
-      fi_ptr = gi_ptr->functions[f_ix];
-
-      size += 2 /* tag_length itself */
-              + GCOV_TAG_FUNCTION_LENGTH; /* ident, lineno_cksum, cfg_cksm */
-
-      ci_ptr = fi_ptr->ctrs;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-        {
-          if (!gcov_counter_active (gi_ptr, t_ix))
-            continue;
-
-          n_counts = ci_ptr->num;
-          size += 2 + GCOV_TAG_COUNTER_LENGTH (n_counts);
-          ci_ptr++;
-        }
-    }
-
-  size += 1;
-
-  return size*4;
-}
-
-/* Write profile data (including summary and module grouping information,
-   if available, to file.  */
-
-static void
-gcov_write_gcda_file (struct gcov_info *gi_ptr)
-{
-  const struct gcov_fn_info *gfi_ptr;
-  const struct gcov_ctr_info *ci_ptr;
-  unsigned t_ix, f_ix, n_counts, length;
-  int error = 0;
-  gcov_position_t eof_pos1 = 0;
-
-  /* Write out the data.  */
-  gcov_seek (0);
-  gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
-  gcov_write_unsigned (gi_ptr->stamp);
-
-  if (summary_pos)
-     gcov_seek (summary_pos);
-  gcc_assert (!summary_pos || summary_pos == gcov_position ());
-
-  /* Generate whole program statistics.  */
-  gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
-
-  /* Rewrite all the summaries that were after the summary we merged
-     into. This is necessary as the merged summary may have a different
-     size due to the number of non-zero histogram entries changing after
-     merging.  */
-
-  while (sum_buffer)
-    {
-      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
-      next_sum_buffer = sum_buffer->next;
-      free (sum_buffer);
-      sum_buffer = next_sum_buffer;
-    }
-
-  /* Write execution counts for each function.  */
-  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-    {
-      gfi_ptr = gi_ptr->functions[f_ix];
-      gcc_assert (gfi_ptr && gfi_ptr->key == gi_ptr);
-      length = GCOV_TAG_FUNCTION_LENGTH;
-
-      gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
-
-      gcov_write_unsigned (gfi_ptr->ident);
-      gcov_write_unsigned (gfi_ptr->lineno_checksum);
-      gcov_write_unsigned (gfi_ptr->cfg_checksum);
-
-      ci_ptr = gfi_ptr->ctrs;
-      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
-        {
-          if (!gi_ptr->merge[t_ix])
-            continue;
-
-          n_counts = ci_ptr->num;
-          gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
-                                 GCOV_TAG_COUNTER_LENGTH (n_counts));
-          gcov_type *c_ptr = ci_ptr->values;
-          while (n_counts--)
-            gcov_write_counter (*c_ptr++);
-          ci_ptr++;
-        }
-      eof_pos1 = gcov_position ();
-    }
-
-    eof_pos = eof_pos1;
-    /* Write the end marker  */
-    gcov_write_unsigned (0);
-
-    gi_ptr->eof_pos = eof_pos;
-
-    if ((error = gcov_close ()))
-      gcov_error (error  < 0 ?
-                  "profiling:%s:Overflow writing\n" :
-                  "profiling:%s:Error writing\n",
-                   gi_filename);
-}
-
-/* Do some preparation work before calling the actual dumping
-   routine.
-   Return: 1 when module grouping info needs to be dumped,
-           0 otherwise.  */
-
-static int
-gcov_exit_init (void)
-{
-  struct gcov_info *gi_ptr;
-  int dump_module_info = 0;
-
-  dump_module_info = 0;
-  gcov_prefix_strip = 0;
-
-  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)
-    {
-      gcov_object_summary (gi_ptr, &this_program);
-
-      /* The IS_PRIMARY field is overloaded to indicate if this module
-         is FDO/LIPO.  */
-      dump_module_info |= gi_ptr->mod_info->is_primary;
-    }
-
-  gcov_compute_histogram (&this_program);
-
-  gcov_alloc_filename ();
-
-  return dump_module_info;
-}
-
-/* Dump one entry in the gcov_info list (for one object).  */
-
-static void
-gcov_dump_one_gcov (struct gcov_info *gi_ptr)
-{
-  int ret;
-
-  gcov_sort_topn_counter_arrays (gi_ptr);
-
-  GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename,
-                     gi_filename_up);
-
-  if (gcov_open_by_filename (gi_filename) == -1)
-    return;
-
-  /* Now merge this file.  */
-  ret = gcov_merge_gcda_file (gi_ptr);
-  if (ret != 0 ) return;
-
-  gcov_write_gcda_file (gi_ptr);
-}
-
-#endif /* L_gcov */
-
-#ifdef L_gcov_reset
-
-/* Function that can be called from application to reset counters to zero,
-   in order to collect profile in region of interest.  */
-
-void
-__gcov_reset (void)
-{
-  gcov_clear ();
-  /* Re-enable dumping to support collecting profile in multiple regions
-     of interest.  */
-  gcov_dump_complete = 0;
-}
-
-#endif /* L_gcov_reset */
-
-#ifdef L_gcov_dump
-
-/* Function that can be called from application to write profile collected
-   so far, in order to collect profile in region of interest.  */
-
-void
-__gcov_dump (void)
-{
-  gcov_exit ();
-  /* Prevent profile from being dumped a second time on application exit.  */
-  gcov_dump_complete = 1;
-}
-
-#endif /* L_gcov_dump */
-
-#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_dc
-
-/* Returns 1 if the function global id GID is not valid.  */
-
-static int
-__gcov_is_gid_insane (gcov_type gid)
-{
-  if (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (gid) == 0
-      || EXTRACT_FUNC_ID_FROM_GLOBAL_ID (gid) == 0)
-    return 1;
-  return 0;
-}
-
-/* The profile merging function used for merging direct call counts
-   This function is given array COUNTERS of N_COUNTERS old counters and it
-   reads the same number of counters from the gcov file.  */
-
-void
-__gcov_merge_dc (gcov_type *counters, unsigned n_counters)
-{
-  unsigned i;
-
-  gcc_assert (!(n_counters % 2));
-  for (i = 0; i < n_counters; i += 2)
-    {
-      gcov_type global_id = gcov_read_counter ();
-      gcov_type call_count = gcov_read_counter ();
-
-      /* Note that global id counter may never have been set if no calls were
-	 made from this call-site.  */
-      if (counters[i] && global_id)
-        {
-          /* TODO race condition requires us do the following correction.  */
-          if (__gcov_is_gid_insane (counters[i]))
-            counters[i] = global_id;
-          else if (__gcov_is_gid_insane (global_id))
-            global_id = counters[i];
-
-          gcc_assert (counters[i] == global_id);
-        }
-      else if (global_id)
-	counters[i] = global_id;
-
-      counters[i + 1] += call_count;
-
-      /* Reset. */
-      if (__gcov_is_gid_insane (counters[i]))
-        counters[i] = counters[i + 1] = 0;
-
-      /* Assert that the invariant (global_id == 0) <==> (call_count == 0)
-	 holds true after merging.  */
-      if (counters[i] == 0)
-        counters[i+1] = 0;
-      if (counters[i + 1] == 0)
-        counters[i] = 0;
-    }
-}
-#endif
-
-#ifdef L_gcov_merge_icall_topn
-/* The profile merging function used for merging indirect call counts
-   This function is given array COUNTERS of N_COUNTERS old counters and it
-   reads the same number of counters from the gcov file.  */
-
-void
-__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
-{
-  unsigned i, j, k, m;
-
-  gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
-  for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
-    {
-      gcov_type *value_array = &counters[i + 1];
-      unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1);
-      gcov_type *tmp_array 
-          = (gcov_type *) alloca (tmp_size * sizeof (gcov_type));
-
-      for (j = 0; j < tmp_size; j++)
-        tmp_array[j] = 0;
-
-      for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
-        {
-          tmp_array[j] = value_array[j];
-          tmp_array[j + 1] = value_array [j + 1];
-        }
-
-      /* Skip the number_of_eviction entry.  */
-      gcov_read_counter ();
-      for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
-        {
-          int found = 0;
-          gcov_type global_id = gcov_read_counter ();
-          gcov_type call_count = gcov_read_counter ();
-          for (m = 0; m < j; m += 2)
-            {
-              if (tmp_array[m] == global_id)
-                {
-                  found = 1;
-                  tmp_array[m + 1] += call_count;
-                  break;
-                }
-            }
-          if (!found)
-            {
-              tmp_array[j] = global_id;
-              tmp_array[j + 1] = call_count;
-              j += 2;
-            }
-        }
-      /* Now sort the temp array */
-      gcov_sort_n_vals (tmp_array, j);
-
-      /* Now copy back the top half of the temp array */
-      for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
-        {
-          value_array[k] = tmp_array[k];
-          value_array[k + 1] = tmp_array[k + 1];
-        }
-    }
-}
-#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]++;
-}
-
-/* Atomic update version of __gcov_one_value_profile_body().  */
-static inline void
-__gcov_one_value_profiler_body_atomic (gcov_type *counters, gcov_type value)
-{
-  if (value == counters[0])
-    GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], 1, MEMMODEL_RELAXED);
-  else if (counters[1] == 0)
-    {
-      counters[1] = 1;
-      counters[0] = value;
-    }
-  else
-    GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], -1, MEMMODEL_RELAXED);
-  GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[2], 1, MEMMODEL_RELAXED);
-}
-
-#ifdef L_gcov_indirect_call_topn_profiler
-/* Tries to keep track the most frequent N values in the counters where
-   N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
-   entries are used.
-   counter[0] --- the accumative count of the number of times one entry in
-                  in the counters gets evicted/replaced due to limited capacity.
-                  When this value reaches a threshold, the bottom N values are
-                  cleared.
-   counter[1] through counter[2*N] records the top 2*N values collected so far.
-   Each value is represented by two entries: count[2*i+1] is the ith value, and
-   count[2*i+2] is the number of times the value is seen.  */
-
-static void
-__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
-                                 gcov_unsigned_t topn_val)
-{
-   unsigned i, found = 0, have_zero_count = 0;
-
-   gcov_type *entry;
-   gcov_type *lfu_entry = &counters[1];
-   gcov_type *value_array = &counters[1];
-   gcov_type *num_eviction = &counters[0];
-
-   /* There are 2*topn_val values tracked, each value takes two slots in the
-      counter array */
-   for ( i = 0; i < (topn_val << 2); i += 2)
-     {
-       entry = &value_array[i];
-       if ( entry[0] == value)
-         {
-           entry[1]++ ;
-           found = 1;
-           break;
-         }
-       else if (entry[1] == 0)
-         {
-           lfu_entry = entry;
-           have_zero_count = 1;
-         }
-      else if (entry[1] < lfu_entry[1])
-        lfu_entry = entry;
-     }
-
-   if (found)
-     return;
-
-   /* lfu_entry is either an empty entry or an entry
-      with lowest count, which will be evicted.  */
-   lfu_entry[0] = value;
-   lfu_entry[1] = 1;
-
-#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
-
-   /* Too many evictions -- time to clear bottom entries to 
-      avoid hot values bumping each other out.  */
-   if ( !have_zero_count 
-        && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
-     {
-       unsigned i, j;
-       gcov_type *p, minv;
-       gcov_type* tmp_cnts 
-           = (gcov_type *)alloca (topn_val * sizeof(gcov_type));
-
-       *num_eviction = 0;
-
-       for ( i = 0; i < topn_val; i++ )
-         tmp_cnts[i] = 0;
-
-       /* Find the largest topn_val values from the group of
-          2*topn_val values and put them into tmp_cnts. */
-
-       for ( i = 0; i < 2 * topn_val; i += 2 ) 
-         {
-           p = 0;
-           for ( j = 0; j < topn_val; j++ ) 
-             {
-               if ( !p || tmp_cnts[j] < *p ) 
-                  p = &tmp_cnts[j];
-             }
-            if ( value_array[i + 1] > *p )
-              *p = value_array[i + 1];
-         }
-
-       minv = tmp_cnts[0];
-       for ( j = 1; j < topn_val; j++ )
-         {
-           if (tmp_cnts[j] < minv)
-             minv = tmp_cnts[j];
-         }
-       /* Zero out low value entries  */
-       for ( i = 0; i < 2 * topn_val; i += 2 )
-         {
-           if (value_array[i + 1] < minv) 
-             {
-               value_array[i] = 0;
-               value_array[i + 1] = 0;
-             }
-         }
-     }
-}
-#endif
-
-#ifdef L_gcov_one_value_profiler
-void
-__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
-{
-  __gcov_one_value_profiler_body (counters, value);
-}
-
-void
-__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value)
-{
-  __gcov_one_value_profiler_body_atomic (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);
-}
-
-/* Atomic update version of __gcov_indirect_call_profiler().  */
-void
-__gcov_indirect_call_profiler_atomic (gcov_type* counter, gcov_type value,
-                                      void* cur_func, void* callee_func)
-{
-  if (cur_func == callee_func
-      || (VTABLE_USES_DESCRIPTORS && callee_func
-          && *(void **) cur_func == *(void **) callee_func))
-    __gcov_one_value_profiler_body_atomic (counter, value);
-}
-#endif
-
-
-#ifdef L_gcov_indirect_call_topn_profiler
-extern THREAD_PREFIX gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
-extern THREAD_PREFIX void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
-#ifdef TARGET_VTABLE_USES_DESCRIPTORS
-#define VTABLE_USES_DESCRIPTORS 1
-#else
-#define VTABLE_USES_DESCRIPTORS 0
-#endif
-void
-__gcov_indirect_call_topn_profiler (void *cur_func,
-                                    void *cur_module_gcov_info,
-                                    gcov_unsigned_t cur_func_id)
-{
-  void *callee_func = __gcov_indirect_call_topn_callee;
-  gcov_type *counter = __gcov_indirect_call_topn_counters;
-  /* 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_type global_id 
-          = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
-      global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
-      __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL);
-      __gcov_indirect_call_topn_callee = 0;
-    }
-}
-
-#endif
-
-#ifdef L_gcov_direct_call_profiler
-extern THREAD_PREFIX gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN;
-extern THREAD_PREFIX void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN;
-/* Direct call profiler. */
-void
-__gcov_direct_call_profiler (void *cur_func,
-			     void *cur_module_gcov_info,
-			     gcov_unsigned_t cur_func_id)
-{
-  if (cur_func == __gcov_direct_call_callee)
-    {
-      gcov_type global_id 
-          = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
-      global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
-      __gcov_direct_call_counters[0] = global_id;
-      __gcov_direct_call_counters[1]++;
-      __gcov_direct_call_callee = 0;
-    }
-}
-#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
-/* Bitwise-OR VALUE into COUNTER.  */
-
-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)
-{
-  pid_t pid;
-  extern __gthread_mutex_t __gcov_flush_mx;
-  __gcov_flush ();
-  pid = fork ();
-  if (pid == 0)
-    __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
-  return pid;
-}
-#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: libgcc/libgcov.h
===================================================================
--- libgcc/libgcov.h	(revision 0)
+++ libgcc/libgcov.h	(revision 0)
@@ -0,0 +1,295 @@ 
+/* Header file for libgcov-*.c.
+   Copyright (C) 1996-2014 Free Software Foundation, Inc.
+   Contributed by Bob Manson <manson@cygnus.com>.
+   Completely remangled by Nathan Sidwell <nathan@codesourcery.com>.
+
+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/>.  */
+
+#ifndef GCC_LIBGCOV_H
+#define GCC_LIBGCOV_H
+
+/* work around the poisoned malloc/calloc in system.h.  */
+#ifndef xmalloc
+#define xmalloc malloc
+#endif
+#ifndef xcalloc
+#define xcalloc calloc
+#endif
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+#define THREAD_PREFIX __thread
+#else
+#define THREAD_PREFIX
+#endif
+
+#if defined(inhibit_libc)
+#define IN_LIBGCOV (-1)
+#else
+#define IN_LIBGCOV 1
+#if defined(L_gcov)
+#define GCOV_LINKAGE /* nothing */
+#endif
+#endif
+
+#undef FUNC_ID_WIDTH
+#undef FUNC_ID_MASK
+
+#if BITS_PER_UNIT == 8
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
+typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
+#if LONG_LONG_TYPE_SIZE > 32
+typedef signed gcov_type __attribute__ ((mode (DI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
+#else
+typedef signed gcov_type __attribute__ ((mode (SI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
+#endif
+#else   /* BITS_PER_UNIT != 8  */
+#if BITS_PER_UNIT == 16
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
+typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
+#if LONG_LONG_TYPE_SIZE > 32
+typedef signed gcov_type __attribute__ ((mode (SI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
+#else
+typedef signed gcov_type __attribute__ ((mode (HI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
+#endif
+#else  /* BITS_PER_UNIT != 16  */
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
+typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
+#if LONG_LONG_TYPE_SIZE > 32
+typedef signed gcov_type __attribute__ ((mode (HI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
+#else
+typedef signed gcov_type __attribute__ ((mode (QI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
+typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
+#endif
+#endif /* BITS_PER_UNIT == 16  */
+
+#endif  /* BITS_PER_UNIT == 8  */
+
+#if LONG_LONG_TYPE_SIZE > 32
+#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_8
+#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_8
+#else
+#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_4
+#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_4
+#endif
+
+#undef EXTRACT_MODULE_ID_FROM_GLOBAL_ID
+#undef EXTRACT_FUNC_ID_FROM_GLOBAL_ID
+#undef GEN_FUNC_GLOBAL_ID
+#define EXTRACT_MODULE_ID_FROM_GLOBAL_ID(gid) \
+                (gcov_unsigned_t)(((gid) >> FUNC_ID_WIDTH) & FUNC_ID_MASK)
+#define EXTRACT_FUNC_ID_FROM_GLOBAL_ID(gid) \
+                (gcov_unsigned_t)((gid) & FUNC_ID_MASK)
+#define GEN_FUNC_GLOBAL_ID(m,f) ((((gcov_type) (m)) << FUNC_ID_WIDTH) | (f))
+
+
+#if defined (TARGET_POSIX_IO)
+#define GCOV_LOCKED 1
+#else
+#define GCOV_LOCKED 0
+#endif
+
+#define gcov_var __gcov_var
+#define gcov_open __gcov_open
+#define gcov_close __gcov_close
+#define gcov_write_tag_length __gcov_write_tag_length
+#define gcov_position __gcov_position
+#define gcov_seek __gcov_seek
+#define gcov_rewrite __gcov_rewrite
+#define gcov_truncate __gcov_truncate
+#define gcov_is_error __gcov_is_error
+#define gcov_write_unsigned __gcov_write_unsigned
+#define gcov_write_counter __gcov_write_counter
+#define gcov_write_summary __gcov_write_summary
+#define gcov_write_module_info __gcov_write_module_info
+#define gcov_read_unsigned __gcov_read_unsigned
+#define gcov_read_counter __gcov_read_counter
+#define gcov_read_summary __gcov_read_summary
+#define gcov_read_module_info __gcov_read_module_info
+#define gcov_sort_n_vals __gcov_sort_n_vals
+
+/* Poison these, so they don't accidentally slip in.  */
+#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
+#pragma GCC poison /*gcov_read_string gcov_sync*/ gcov_time gcov_magic
+
+#ifdef HAVE_GAS_HIDDEN
+#define ATTRIBUTE_HIDDEN  __attribute__ ((__visibility__ ("hidden")))
+#else
+#define ATTRIBUTE_HIDDEN
+#endif
+
+#include "gcov-io.h"
+
+/* Structures embedded in coveraged program.  The structures generated
+   by write_profile must match these.  */
+
+/* Information about counters for a single function.  */
+struct gcov_ctr_info
+{
+  gcov_unsigned_t num;		/* number of counters.  */
+  gcov_type *values;		/* their values.  */
+};
+
+/* Information about a single function.  This uses the trailing array
+   idiom. The number of counters is determined from the merge pointer
+   array in gcov_info.  The key is used to detect which of a set of
+   comdat functions was selected -- it points to the gcov_info object
+   of the object file containing the selected comdat function.  */
+
+struct gcov_fn_info
+{
+  const struct gcov_info *key;		/* comdat key */
+  gcov_unsigned_t ident;		/* unique ident of function */
+  gcov_unsigned_t lineno_checksum;	/* function lineo_checksum */
+  gcov_unsigned_t cfg_checksum;	/* function cfg checksum */
+  struct gcov_ctr_info ctrs[0];		/* instrumented counters */
+};
+
+/* Type of function used to merge counters.  */
+typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
+
+/* Information about a single object file.  */
+struct gcov_info
+{
+  gcov_unsigned_t version;	/* expected version number */
+  struct gcov_module_info *mod_info; /* addtional module info.  */
+  struct gcov_info *next;	/* link to next, used by libgcov */
+
+  gcov_unsigned_t stamp;	/* uniquifying time stamp */
+  const char *filename;		/* output file name */
+  gcov_unsigned_t eof_pos;      /* end position of profile data */
+  gcov_merge_fn merge[GCOV_COUNTERS];  /* merge functions (null for
+					  unused) */
+
+  unsigned n_functions;		/* number of functions */
+  const struct gcov_fn_info *const *functions; /* pointer to pointers
+					          to function information  */
+};
+
+/* Information about a single imported module.  */
+struct dyn_imp_mod
+{
+  const struct gcov_info *imp_mod;
+  double weight;
+};
+
+/* Register a new object file module.  */
+extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
+
+/* Set sampling rate to RATE.  */
+extern void __gcov_set_sampling_rate (unsigned int rate);
+
+/* Called before fork, to avoid double counting.  */
+extern void __gcov_flush (void) ATTRIBUTE_HIDDEN;
+
+/* Function to reset all counters to 0.  */
+extern void __gcov_reset (void);
+
+/* Function to enable early write of profile information so far.  */
+extern void __gcov_dump (void);
+
+/* The merge function that just sums the counters.  */
+extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function to choose the most common value.  */
+extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function to choose the most common difference between
+   consecutive values.  */
+extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function that just ors the counters together.  */
+extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function used for direct call counters.  */
+extern void __gcov_merge_dc (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function used for indirect call counters.  */
+extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The profiler functions.  */
+extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
+extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
+extern void __gcov_one_value_profiler (gcov_type *, gcov_type);
+extern void __gcov_one_value_profiler_atomic (gcov_type *, gcov_type);
+extern void __gcov_indirect_call_profiler (gcov_type *, gcov_type, void *, void *);
+extern void __gcov_indirect_call_profiler_atomic (gcov_type *, gcov_type, void *, void *);
+extern void __gcov_indirect_call_topn_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
+extern void __gcov_direct_call_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
+extern void __gcov_average_profiler (gcov_type *, gcov_type);
+extern void __gcov_ior_profiler (gcov_type *, gcov_type);
+extern void __gcov_sort_n_vals (gcov_type *value_array, int n);
+
+#ifndef inhibit_libc
+/* The wrappers around some library functions.  */
+extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
+extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN;
+extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN;
+extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN;
+extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN;
+extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
+extern int __gcov_execve (const char *, char  *const [], char *const [])
+  ATTRIBUTE_HIDDEN;
+
+/* Functions that only available only in libgcov.  */
+GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t)
+    ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
+				      const struct gcov_summary *)
+    ATTRIBUTE_HIDDEN;
+
+GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info)
+    ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE const struct dyn_imp_mod **
+gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len)
+    ATTRIBUTE_HIDDEN;
+/*staic void gcov_rewrite (void); */
+GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN;
+
+#endif /* !inhibit_libc */
+
+#endif /* GCC_LIBGCOV_H */
Index: libgcc/libgcov-driver-system.c
===================================================================
--- libgcc/libgcov-driver-system.c	(revision 0)
+++ libgcc/libgcov-driver-system.c	(revision 0)
@@ -0,0 +1,203 @@ 
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2014 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/>.  */
+
+/* A utility function for outputing errors.  */
+
+static int __attribute__((format(printf, 1, 2)))
+gcov_error (const char *fmt, ...)
+{
+  int ret;
+  va_list argp;
+  va_start (argp, fmt);
+  ret = vfprintf (stderr, fmt, argp);
+  va_end (argp);
+  return ret;
+}
+
+/* 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)
+	  {
+            gcov_error ("profiling:%s:Cannot create directory\n", filename);
+            *s = sep;
+	    return -1;
+	  };
+
+	*s = sep;
+      };
+  return 0;
+#endif
+}
+
+static void
+allocate_filename_struct (struct gcov_filename_aux *gf)
+{
+  const char *gcov_prefix;
+  int gcov_prefix_strip = 0;
+  size_t prefix_length;
+  char *gi_filename_up;
+
+  gcc_assert (gf);
+  {
+    /* 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 *) xmalloc (prefix_length + gcov_max_filename + 2);
+  if (prefix_length)
+    memcpy (gi_filename, gcov_prefix, prefix_length);
+  gi_filename_up = gi_filename + prefix_length;
+
+  gf->gi_filename_up = gi_filename_up;
+  gf->prefix_length = prefix_length;
+  gf->gcov_prefix_strip = gcov_prefix_strip;
+}
+
+/* Open a gcda file specified by GI_FILENAME.
+   Return -1 on error.  Return 0 on success.  */
+
+static int
+gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+{
+  int gcov_prefix_strip;
+  size_t prefix_length;
+  char *gi_filename_up;
+  const char *fname, *s;
+
+  gcov_prefix_strip = gf->gcov_prefix_strip;
+  gi_filename_up = gf->gi_filename_up;
+  prefix_length = gf->prefix_length;
+  fname = gi_ptr->filename;
+
+  /* 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);
+
+  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))
+        {
+          gcov_error ("profiling:%s:Skip\n", gi_filename);
+          return -1;
+        }
+      if (!gcov_open (gi_filename))
+        {
+          gcov_error ("profiling:%s:Cannot open\n", gi_filename);
+          return -1;
+        }
+    }
+
+  return 0;
+}
Index: libgcc/libgcov-profiler.c
===================================================================
--- libgcc/libgcov-profiler.c	(revision 0)
+++ libgcc/libgcov-profiler.c	(revision 0)
@@ -0,0 +1,351 @@ 
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2013 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 "libgcov.h"
+#if !defined(inhibit_libc)
+
+#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]++;
+}
+
+/* Atomic update version of __gcov_one_value_profile_body().  */
+static inline void
+__gcov_one_value_profiler_body_atomic (gcov_type *counters, gcov_type value)
+{
+  if (value == counters[0])
+    GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], 1, MEMMODEL_RELAXED);
+  else if (counters[1] == 0)
+    {
+      counters[1] = 1;
+      counters[0] = value;
+    }
+  else
+    GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], -1, MEMMODEL_RELAXED);
+  GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[2], 1, MEMMODEL_RELAXED);
+}
+
+#ifdef L_gcov_one_value_profiler
+void
+__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
+{
+  __gcov_one_value_profiler_body (counters, value);
+}
+
+void
+__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+  __gcov_one_value_profiler_body_atomic (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);
+}
+
+/* Atomic update version of __gcov_indirect_call_profiler().  */
+void
+__gcov_indirect_call_profiler_atomic (gcov_type* counter, gcov_type value,
+                                      void* cur_func, void* callee_func)
+{
+  if (cur_func == callee_func
+      || (VTABLE_USES_DESCRIPTORS && callee_func
+          && *(void **) cur_func == *(void **) callee_func))
+    __gcov_one_value_profiler_body_atomic (counter, value);
+}
+#endif
+
+#ifdef L_gcov_indirect_call_topn_profiler
+/* Tries to keep track the most frequent N values in the counters where
+   N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
+   entries are used.
+   counter[0] --- the accumative count of the number of times one entry in
+                  in the counters gets evicted/replaced due to limited capacity.
+                  When this value reaches a threshold, the bottom N values are
+                  cleared.
+   counter[1] through counter[2*N] records the top 2*N values collected so far.
+   Each value is represented by two entries: count[2*i+1] is the ith value, and
+   count[2*i+2] is the number of times the value is seen.  */
+
+static void
+__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
+                                 gcov_unsigned_t topn_val)
+{
+   unsigned i, found = 0, have_zero_count = 0;
+
+   gcov_type *entry;
+   gcov_type *lfu_entry = &counters[1];
+   gcov_type *value_array = &counters[1];
+   gcov_type *num_eviction = &counters[0];
+
+   /* There are 2*topn_val values tracked, each value takes two slots in the
+      counter array */
+   for ( i = 0; i < (topn_val << 2); i += 2)
+     {
+       entry = &value_array[i];
+       if ( entry[0] == value)
+         {
+           entry[1]++ ;
+           found = 1;
+           break;
+         }
+       else if (entry[1] == 0)
+         {
+           lfu_entry = entry;
+           have_zero_count = 1;
+         }
+      else if (entry[1] < lfu_entry[1])
+        lfu_entry = entry;
+     }
+
+   if (found)
+     return;
+
+   /* lfu_entry is either an empty entry or an entry
+      with lowest count, which will be evicted.  */
+   lfu_entry[0] = value;
+   lfu_entry[1] = 1;
+
+#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
+
+   /* Too many evictions -- time to clear bottom entries to
+      avoid hot values bumping each other out.  */
+   if ( !have_zero_count
+        && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
+     {
+       unsigned i, j;
+       gcov_type *p, minv;
+       gcov_type* tmp_cnts
+           = (gcov_type *)alloca (topn_val * sizeof(gcov_type));
+
+       *num_eviction = 0;
+
+       for ( i = 0; i < topn_val; i++ )
+         tmp_cnts[i] = 0;
+
+       /* Find the largest topn_val values from the group of
+          2*topn_val values and put them into tmp_cnts. */
+
+       for ( i = 0; i < 2 * topn_val; i += 2 )
+         {
+           p = 0;
+           for ( j = 0; j < topn_val; j++ )
+             {
+               if ( !p || tmp_cnts[j] < *p )
+                  p = &tmp_cnts[j];
+             }
+            if ( value_array[i + 1] > *p )
+              *p = value_array[i + 1];
+         }
+
+       minv = tmp_cnts[0];
+       for ( j = 1; j < topn_val; j++ )
+         {
+           if (tmp_cnts[j] < minv)
+             minv = tmp_cnts[j];
+         }
+       /* Zero out low value entries  */
+       for ( i = 0; i < 2 * topn_val; i += 2 )
+         {
+           if (value_array[i + 1] < minv)
+             {
+               value_array[i] = 0;
+               value_array[i + 1] = 0;
+             }
+         }
+     }
+}
+
+/* Pointer to the indirect-call counters (per call-site counters).
+   Initialized by the caller.  */
+THREAD_PREFIX gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
+
+/* Indirect call callee address.  */
+THREAD_PREFIX void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
+
+#ifdef TARGET_VTABLE_USES_DESCRIPTORS
+#define VTABLE_USES_DESCRIPTORS 1
+#else
+#define VTABLE_USES_DESCRIPTORS 0
+#endif
+
+void
+__gcov_indirect_call_topn_profiler (void *cur_func,
+                                    void *cur_module_gcov_info,
+                                    gcov_unsigned_t cur_func_id)
+{
+  void *callee_func = __gcov_indirect_call_topn_callee;
+  gcov_type *counter = __gcov_indirect_call_topn_counters;
+  /* 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_type global_id
+          = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+      global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+      __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL);
+      __gcov_indirect_call_topn_callee = 0;
+    }
+}
+
+#endif
+
+#ifdef L_gcov_direct_call_profiler
+/* Pointer to the direct-call counters (per call-site counters).
+   Initialized by the caller.  */
+THREAD_PREFIX gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN;
+
+/* Direct call callee address.  */
+THREAD_PREFIX void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN;
+
+/* Direct call profiler. */
+void
+__gcov_direct_call_profiler (void *cur_func,
+			     void *cur_module_gcov_info,
+			     gcov_unsigned_t cur_func_id)
+{
+  if (cur_func == __gcov_direct_call_callee)
+    {
+      gcov_type global_id
+          = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+      global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+      __gcov_direct_call_counters[0] = global_id;
+      __gcov_direct_call_counters[1]++;
+      __gcov_direct_call_callee = 0;
+    }
+}
+#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
+/* Bitwise-OR VALUE into COUNTER.  */
+
+void
+__gcov_ior_profiler (gcov_type *counters, gcov_type value)
+{
+  *counters |= value;
+}
+#endif
+
+#endif /* inhibit_libc */
Index: libgcc/libgcov-driver.c
===================================================================
--- libgcc/libgcov-driver.c	(revision 0)
+++ libgcc/libgcov-driver.c	(revision 0)
@@ -0,0 +1,996 @@ 
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2013 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 "libgcov.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))) {}
+#endif
+
+#else /* !inhibit_libc */
+
+#include <string.h>
+#if GCOV_LOCKED
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef L_gcov
+#include "gcov-io.c"
+
+/* The following functions can be called from outside of this file.  */
+extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
+extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
+extern void set_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
+extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
+extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
+extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
+extern struct gcov_info *get_gcov_list (void) ATTRIBUTE_HIDDEN;
+
+/* Create a strong reference to these symbols so that they are
+   unconditionally pulled into the instrumented binary, even when
+   the only reference is a weak reference. This is necessary because
+   we are using weak references to handle older compilers that
+   pre-date these new functions. A subtlety of the linker is that
+   it will only resolve weak references defined within archive libraries
+   when there is a string reference to something else defined within
+   the same object file. Since these two functions are defined within
+   their own object files (using L_gcov_reset and L_gcov_dump), they
+   would not get resolved. Since there are symbols within the main L_gcov
+   section that are strongly referenced during -fprofile-generate builds,
+   these symbols will always need to be resolved.  */
+void (*__gcov_dummy_ref1)(void) = &__gcov_reset;
+void (*__gcov_dummy_ref2)(void) = &__gcov_dump;
+
+/* Default callback function for profile instrumentation callback.  */
+extern void __coverage_callback (gcov_type, int);
+__attribute__((weak)) void
+__coverage_callback (gcov_type funcdef_no __attribute__ ((unused)),
+                     int edge_no __attribute__ ((unused)))
+{
+   /* nothing */
+}
+
+/* Flag when the profile has already been dumped via __gcov_dump().  */
+static int gcov_dump_complete;
+
+/* A global function that get the vaule of gcov_dump_complete.  */
+
+int
+get_gcov_dump_complete (void)
+{
+  return gcov_dump_complete;
+}
+
+/* A global functino that set the vaule of gcov_dump_complete. Will
+   be used in __gcov_dump() in libgcov-interface.c.  */
+
+void
+set_gcov_dump_complete (void)
+{
+  gcov_dump_complete = 1;
+}
+
+/* A global functino that set the vaule of gcov_dump_complete. Will
+   be used in __gcov_reset() in libgcov-interface.c.  */
+
+void
+reset_gcov_dump_complete (void)
+{
+  gcov_dump_complete = 0;
+}
+
+/* A utility function for outputing errors.  */
+static int gcov_error (const char *fmt, ...);
+
+struct gcov_summary_buffer
+{
+  struct gcov_summary_buffer *next;
+  struct gcov_summary summary;
+};
+
+/* Chain of per-object gcov structures.  */
+static struct gcov_info *__gcov_list;
+
+/* Set the head of gcov_list.  */
+void
+set_gcov_list (struct gcov_info *head)
+{
+  __gcov_list = head;
+}
+
+/* Return the head of gcov_list.  */
+struct gcov_info *
+get_gcov_list (void)
+{
+  return __gcov_list;
+}
+
+/* Size of the longest file name. */
+static size_t gcov_max_filename = 0;
+
+extern gcov_unsigned_t __gcov_sampling_period;
+static int gcov_sampling_period_initialized = 0;
+
+/* Unique identifier assigned to each module (object file).  */
+static gcov_unsigned_t gcov_cur_module_id = 0;
+
+/* Dynamic call graph build and form module groups.  */
+void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
+void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
+
+/* Add an unsigned value to the current crc */
+
+static gcov_unsigned_t
+crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
+{
+  unsigned ix;
+
+  for (ix = 32; ix--; value <<= 1)
+    {
+      unsigned feedback;
+
+      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
+      crc32 <<= 1;
+      crc32 ^= feedback;
+    }
+
+  return crc32;
+}
+
+/* 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 __attribute__ ((unused)),
+              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);
+
+      if (filename)
+        gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
+                   filename, e, v);
+      else
+        gcov_error ("profiling:Version mismatch - expected %.4s got %.4s\n", e, v);
+      return 0;
+    }
+  return 1;
+}
+
+/* Insert counter VALUE into HISTOGRAM.  */
+
+static void
+gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
+{
+  unsigned i;
+
+  i = gcov_histo_index(value);
+  histogram[i].num_counters++;
+  histogram[i].cum_value += value;
+  if (value < histogram[i].min_value)
+    histogram[i].min_value = value;
+}
+
+/* Computes a histogram of the arc counters to place in the summary SUM.  */
+
+static void
+gcov_compute_histogram (struct gcov_summary *sum)
+{
+  struct gcov_info *gi_ptr;
+  const struct gcov_fn_info *gfi_ptr;
+  const struct gcov_ctr_info *ci_ptr;
+  struct gcov_ctr_summary *cs_ptr;
+  unsigned t_ix, f_ix, ctr_info_ix, ix;
+  int h_ix;
+
+  /* This currently only applies to arc counters.  */
+  t_ix = GCOV_COUNTER_ARCS;
+
+  /* First check if there are any counts recorded for this counter.  */
+  cs_ptr = &(sum->ctrs[t_ix]);
+  if (!cs_ptr->num)
+    return;
+
+  for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
+    {
+      cs_ptr->histogram[h_ix].num_counters = 0;
+      cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max;
+      cs_ptr->histogram[h_ix].cum_value = 0;
+    }
+
+  /* Walk through all the per-object structures and record each of
+     the count values in histogram.  */
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      if (!gi_ptr->merge[t_ix])
+        continue;
+
+      /* Find the appropriate index into the gcov_ctr_info array
+         for the counter we are currently working on based on the
+         existence of the merge function pointer for this object.  */
+      for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++)
+        {
+          if (gi_ptr->merge[ix])
+            ctr_info_ix++;
+        }
+      for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
+        {
+          gfi_ptr = gi_ptr->functions[f_ix];
+
+          if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+            continue;
+
+          ci_ptr = &gfi_ptr->ctrs[ctr_info_ix];
+          for (ix = 0; ix < ci_ptr->num; ix++)
+            gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]);
+        }
+    }
+}
+
+/* This funtions computes the program level summary and the histo-gram.
+   It computes and returns CRC32 and stored summary in THIS_PRG.  */
+
+static gcov_unsigned_t
+gcov_exit_compute_summary (struct gcov_summary *this_prg)
+{
+  struct gcov_info *gi_ptr;
+  const struct gcov_fn_info *gfi_ptr;
+  struct gcov_ctr_summary *cs_ptr;
+  const struct gcov_ctr_info *ci_ptr;
+  int f_ix;
+  unsigned t_ix;
+  gcov_unsigned_t c_num;
+  gcov_unsigned_t crc32 = 0;
+
+  /* Find the totals for this execution.  */
+  memset (this_prg, 0, sizeof (*this_prg));
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
+      crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
+
+      for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
+        {
+          gfi_ptr = gi_ptr->functions[f_ix];
+
+          if (gfi_ptr && gfi_ptr->key != gi_ptr)
+            gfi_ptr = 0;
+
+          crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
+          crc32 = crc32_unsigned (crc32,
+                                  gfi_ptr ? gfi_ptr->lineno_checksum : 0);
+          if (!gfi_ptr)
+            continue;
+
+          ci_ptr = gfi_ptr->ctrs;
+          for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
+            {
+              if (!gi_ptr->merge[t_ix])
+                continue;
+
+              cs_ptr = &(this_prg->ctrs[t_ix]);
+              cs_ptr->num += ci_ptr->num;
+              crc32 = crc32_unsigned (crc32, 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++;
+            }
+        }
+    }
+  gcov_compute_histogram (this_prg);
+  return crc32;
+}
+
+/* gcda filename.  */
+static char *gi_filename;
+/* buffer for summary from other programs to be written out. */
+static struct gcov_summary_buffer *sum_buffer;
+
+/* A struct that bundles all the related information about the
+   gcda filename.  */
+struct gcov_filename_aux{
+  char *gi_filename_up;
+  int gcov_prefix_strip;
+  size_t prefix_length;
+};
+
+/* Including system dependent components. */
+#include "libgcov-driver-system.c"
+
+/* This function merges counters in GI_PTR to an existing gcda file.
+   Return 0 on success.
+   Return -1 on error. In this case, caller will goto read_fatal.  */
+
+static int
+gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
+                      struct gcov_summary *prg_p,
+                      struct gcov_summary *this_prg,
+                      gcov_position_t *summary_pos_p,
+                      gcov_position_t *eof_pos_p,
+                      gcov_unsigned_t crc32)
+{
+  gcov_unsigned_t tag, length, version, stamp;
+  unsigned t_ix, f_ix;
+  int error = 0;
+  struct gcov_summary_buffer **sum_tail = &sum_buffer;
+
+  version = gcov_read_unsigned ();
+  if (!gcov_version (gi_ptr, version, gi_filename))
+    return -1;
+
+  stamp = gcov_read_unsigned ();
+  if (stamp != gi_ptr->stamp)
+    /* Read from a different compilation. Overwrite the file.  */
+    return 0;
+
+  /* Look for program summary.  */
+  for (f_ix = ~0u;;)
+    {
+      struct gcov_summary tmp;
+
+      *eof_pos_p = gcov_position ();
+      tag = gcov_read_unsigned ();
+      if (tag != GCOV_TAG_PROGRAM_SUMMARY)
+        break;
+
+      length = gcov_read_unsigned ();
+      gcov_read_summary (&tmp);
+      if ((error = gcov_is_error ()))
+        goto read_error;
+      if (*summary_pos_p)
+        {
+          /* Save all summaries after the one that will be
+             merged into below. These will need to be rewritten
+             as histogram merging may change the number of non-zero
+             histogram entries that will be emitted, and thus the
+             size of the merged summary.  */
+          (*sum_tail) = (struct gcov_summary_buffer *)
+              malloc (sizeof(struct gcov_summary_buffer));
+          (*sum_tail)->summary = tmp;
+          (*sum_tail)->next = 0;
+          sum_tail = &((*sum_tail)->next);
+          goto next_summary;
+        }
+      if (tmp.checksum != crc32)
+        goto next_summary;
+
+      for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
+        if (tmp.ctrs[t_ix].num != this_prg->ctrs[t_ix].num)
+          goto next_summary;
+      *prg_p = tmp;
+      *summary_pos_p = *eof_pos_p;
+
+      next_summary:;
+    }
+
+  /* Merge execution counts for each function.  */
+  for (f_ix = 0; f_ix != gi_ptr->n_functions;
+       f_ix++, tag = gcov_read_unsigned ())
+    {
+      const struct gcov_ctr_info *ci_ptr;
+      const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+
+      if (tag != GCOV_TAG_FUNCTION)
+        goto read_mismatch;
+
+      length = gcov_read_unsigned ();
+      if (!length)
+        /* This function did not appear in the other program.
+           We have nothing to merge.  */
+        continue;
+
+      /* Check function.  */
+      if (length != GCOV_TAG_FUNCTION_LENGTH)
+        goto read_mismatch;
+
+      gcc_assert (gfi_ptr && gfi_ptr->key == gi_ptr);
+
+      if (gcov_read_unsigned () != gfi_ptr->ident
+          || gcov_read_unsigned () != gfi_ptr->lineno_checksum
+          || gcov_read_unsigned () != gfi_ptr->cfg_checksum)
+         goto read_mismatch;
+
+      ci_ptr = gfi_ptr->ctrs;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+        {
+          gcov_merge_fn merge = gi_ptr->merge[t_ix];
+
+          if (!merge)
+            continue;
+
+          tag = gcov_read_unsigned ();
+          length = gcov_read_unsigned ();
+          if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
+              || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
+            goto read_mismatch;
+          (*merge) (ci_ptr->values, ci_ptr->num);
+          ci_ptr++;
+        }
+        if ((error = gcov_is_error ()))
+          goto read_error;
+    }
+  if (tag && tag != GCOV_TAG_MODULE_INFO)
+    {
+    read_mismatch:;
+      gcov_error ("profiling:%s:Merge mismatch for %s\n",
+                  gi_filename, f_ix + 1 ? "function" : "summaries");
+      return -1;
+    }
+
+  return 0;
+
+read_error:;
+  gcov_error (error < 0 ? "profiling:%s:Overflow merging\n"
+                : "profiling:%s:Error merging\n", gi_filename);
+  return -1;
+}
+
+/* Write counters in GI_PTR and the summary in PRG to a gcda file. In
+   the case of appending to an existing file, SUMMARY_POS will be non-zero.
+   We will write the file starting from SUMMAY_POS.  */
+
+static void
+gcov_exit_write_gcda (struct gcov_info *gi_ptr,
+                      const struct gcov_summary *prg_p,
+                      const gcov_position_t eof_pos,
+                      const gcov_position_t summary_pos)
+
+{
+  const struct gcov_ctr_info *ci_ptr;
+  unsigned t_ix, f_ix, n_counts, length;
+  gcov_position_t eof_pos1 = 0;
+  struct gcov_summary_buffer *next_sum_buffer;
+
+  /* Write out the data.  */
+  if (!eof_pos)
+    {
+      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
+      gcov_write_unsigned (gi_ptr->stamp);
+    }
+
+  if (summary_pos)
+     gcov_seek (summary_pos);
+  gcc_assert (!summary_pos || summary_pos == gcov_position ());
+
+  /* Generate whole program statistics.  */
+  gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p);
+
+  /* Rewrite all the summaries that were after the summary we merged
+     into. This is necessary as the merged summary may have a different
+     size due to the number of non-zero histogram entries changing after
+     merging.  */
+
+  while (sum_buffer)
+    {
+      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
+      next_sum_buffer = sum_buffer->next;
+      free (sum_buffer);
+      sum_buffer = next_sum_buffer;
+    }
+
+  /* Write execution counts for each function.  */
+  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+    {
+      const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+      gcc_assert (gfi_ptr && gfi_ptr->key == gi_ptr);
+      length = GCOV_TAG_FUNCTION_LENGTH;
+
+      gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
+
+      gcov_write_unsigned (gfi_ptr->ident);
+      gcov_write_unsigned (gfi_ptr->lineno_checksum);
+      gcov_write_unsigned (gfi_ptr->cfg_checksum);
+
+      ci_ptr = gfi_ptr->ctrs;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+        {
+          if (!gi_ptr->merge[t_ix])
+            continue;
+
+          n_counts = ci_ptr->num;
+          gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
+                                 GCOV_TAG_COUNTER_LENGTH (n_counts));
+          gcov_type *c_ptr = ci_ptr->values;
+          while (n_counts--)
+            gcov_write_counter (*c_ptr++);
+          ci_ptr++;
+        }
+      eof_pos1 = gcov_position ();
+    }
+
+    /* Write the end marker  */
+    gcov_write_unsigned (0);
+    gi_ptr->eof_pos = eof_pos1;
+}
+
+/* Helper function for merging summary.
+   Return -1 on error. Return 0 on success.  */
+
+static int
+gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *prg,
+                         struct gcov_summary *this_prg, gcov_unsigned_t crc32,
+                         struct gcov_summary *all_prg __attribute__ ((unused)))
+{
+  struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
+  unsigned t_ix;
+#if !GCOV_LOCKED
+  /* summary for all instances of program.  */
+  struct gcov_ctr_summary *cs_all;
+#endif
+
+  /* Merge the summaries.  */
+  for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
+    {
+      cs_prg = &(prg->ctrs[t_ix]);
+      cs_tprg = &(this_prg->ctrs[t_ix]);
+      cs_all = &(all_prg->ctrs[t_ix]);
+
+      if (gi_ptr->merge[t_ix])
+        {
+          if (!cs_prg->runs++)
+            cs_prg->num = cs_tprg->num;
+          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;
+          if (cs_prg->runs == 1)
+            memcpy (cs_prg->histogram, cs_tprg->histogram,
+                    sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
+          else
+            gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram);
+        }
+      else if (cs_prg->runs)
+        return -1;
+
+      if (!cs_all->runs && cs_prg->runs)
+        memcpy (cs_all, cs_prg, sizeof (*cs_all));
+      else if (!all_prg->checksum
+               && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
+               /* Don't compare the histograms, which may have slight
+                   variations depending on the order they were updated
+                   due to the truncating integer divides used in the
+                   merge.  */
+                && memcmp (cs_all, cs_prg,
+                           sizeof (*cs_all) - (sizeof (gcov_bucket_type)
+                                               * GCOV_HISTOGRAM_SIZE)))
+        {
+          gcov_error ("profiling:%s:Invocation mismatch - "
+              "some data files may have been removed%s\n",
+          gi_filename, GCOV_LOCKED
+          ? "" : " or concurrent update without locking support");
+          all_prg->checksum = ~0u;
+        }
+    }
+
+  prg->checksum = crc32;
+
+  return 0;
+}
+
+/* Sort N entries in VALUE_ARRAY in descending order.
+   Each entry in VALUE_ARRAY has two values. The sorting
+   is based on the second value.  */
+
+GCOV_LINKAGE  void
+gcov_sort_n_vals (gcov_type *value_array, int n)
+{
+  int j, k;
+  for (j = 2; j < n; j += 2)
+    {
+      gcov_type cur_ent[2];
+      cur_ent[0] = value_array[j];
+      cur_ent[1] = value_array[j + 1];
+      k = j - 2;
+      while (k >= 0 && value_array[k + 1] < cur_ent[1])
+        {
+          value_array[k + 2] = value_array[k];
+          value_array[k + 3] = value_array[k+1];
+          k -= 2;
+        }
+      value_array[k + 2] = cur_ent[0];
+      value_array[k + 3] = cur_ent[1];
+    }
+}
+
+/* Sort the profile counters for all indirect call sites. Counters
+   for each call site are allocated in array COUNTERS.  */
+
+static void
+gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
+{
+  int i;
+  gcov_type *values;
+  int n = counters->num;
+  gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
+
+  values = counters->values;
+
+  for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
+    {
+      gcov_type *value_array = &values[i + 1];
+      gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
+    }
+}
+
+static void
+gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
+{
+  unsigned int i;
+  int f_ix;
+  const struct gcov_fn_info *gfi_ptr;
+  const struct gcov_ctr_info *ci_ptr;
+
+  for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
+    {
+      gfi_ptr = gi_ptr->functions[f_ix];
+      ci_ptr = gfi_ptr->ctrs;
+      for (i = 0; i < GCOV_COUNTERS; i++)
+        {
+          if (gi_ptr->merge[i] == 0)
+            continue;
+          if (i == GCOV_COUNTER_ICALL_TOPNV)
+            {
+              gcov_sort_icall_topn_counter (ci_ptr);
+              break;
+            }
+          ci_ptr++;
+        }
+     }
+}
+
+/* Dump the coverage counts for one gcov_info object. 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_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
+		     gcov_unsigned_t crc32, struct gcov_summary *all_prg,
+                     struct gcov_summary *this_prg)
+{
+  struct gcov_summary prg; /* summary for this object over all program.  */
+  int error;
+  gcov_unsigned_t tag;
+  gcov_position_t summary_pos = 0;
+  gcov_position_t eof_pos = 0;
+
+  sum_buffer = 0;
+  gcov_sort_topn_counter_arrays (gi_ptr);
+
+  error = gcov_exit_open_gcda_file (gi_ptr, gf);
+  if (error == -1)
+    return;
+
+  tag = gcov_read_unsigned ();
+  if (tag)
+    {
+      /* Merge data from file.  */
+      if (tag != GCOV_DATA_MAGIC)
+        {
+          gcov_error ("profiling:%s:Not a gcov data file\n", gi_filename);
+          goto read_fatal;
+        }
+      error = gcov_exit_merge_gcda (gi_ptr, &prg, this_prg, &summary_pos, &eof_pos,
+				    crc32);
+      if (error == -1)
+        goto read_fatal;
+    }
+
+  gcov_rewrite ();
+
+  if (!summary_pos)
+    {
+      memset (&prg, 0, sizeof (prg));
+      summary_pos = eof_pos;
+    }
+
+  error = gcov_exit_merge_summary (gi_ptr, &prg, this_prg, crc32, all_prg);
+  if (error == -1)
+    goto read_fatal;
+
+  gcov_exit_write_gcda (gi_ptr, &prg, eof_pos, summary_pos);
+  /* fall through */
+
+read_fatal:;
+  if ((error = gcov_close ()))
+    gcov_error (error  < 0 ?
+                "profiling:%s:Overflow writing\n" :
+                "profiling:%s:Error writing\n",
+                gi_filename);
+}
+
+/* Write imported files (auxiliary modules) for primary module GI_PTR
+   into file GI_FILENAME.  */
+
+static void
+gcov_write_import_file (char *gi_filename, struct gcov_info *gi_ptr)
+{
+  char  *gi_imports_filename;
+  const char *gcov_suffix;
+  FILE *imports_file;
+  size_t prefix_length, suffix_length;
+
+  gcov_suffix = getenv ("GCOV_IMPORTS_SUFFIX");
+  if (!gcov_suffix || !strlen (gcov_suffix))
+    gcov_suffix = ".imports";
+  suffix_length = strlen (gcov_suffix);
+  prefix_length = strlen (gi_filename);
+  gi_imports_filename = (char *) alloca (prefix_length + suffix_length + 1);
+  memset (gi_imports_filename, 0, prefix_length + suffix_length + 1);
+  memcpy (gi_imports_filename, gi_filename, prefix_length);
+  memcpy (gi_imports_filename + prefix_length, gcov_suffix, suffix_length);
+  imports_file = fopen (gi_imports_filename, "w");
+  if (imports_file)
+    {
+      const struct dyn_imp_mod **imp_mods;
+      unsigned i, imp_len;
+      imp_mods = gcov_get_sorted_import_module_array (gi_ptr, &imp_len);
+      if (imp_mods)
+        {
+          for (i = 0; i < imp_len; i++)
+	    {
+	      fprintf (imports_file, "%s\n",
+		       imp_mods[i]->imp_mod->mod_info->source_filename);
+	      fprintf (imports_file, "%s%s\n",
+		       imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX);
+	    }
+          free (imp_mods);
+        }
+      fclose (imports_file);
+    }
+}
+
+/* Write out auxiliary module infomation.  */
+
+static void
+gcov_dump_module_info (struct gcov_filename_aux *gf)
+{
+  struct gcov_info *gi_ptr;
+
+  __gcov_compute_module_groups ();
+
+  /* Now write out module group info.  */
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      int error;
+
+      if (gcov_exit_open_gcda_file (gi_ptr, gf) == -1)
+        continue;
+
+      /* Overwrite the zero word at the of the file.  */
+      gcov_rewrite ();
+      gcov_seek (gi_ptr->eof_pos);
+
+      gcov_write_module_infos (gi_ptr);
+      /* Write the end marker  */
+      gcov_write_unsigned (0);
+      gcov_truncate ();
+
+      if ((error = gcov_close ()))
+           gcov_error (error  < 0 ?  "profiling:%s:Overflow writing\n" :
+                                     "profiling:%s:Error writing\n",
+                                     gi_filename);
+      gcov_write_import_file (gi_filename, gi_ptr);
+    }
+
+  __gcov_finalize_dyn_callgraph ();
+}
+
+/* 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.  */
+
+void
+gcov_exit (void)
+{
+  struct gcov_info *gi_ptr;
+  struct gcov_filename_aux gf;
+  gcov_unsigned_t crc32;
+  struct gcov_summary all_prg;
+  struct gcov_summary this_prg;
+  int dump_module_info = 0;
+
+  /* Prevent the counters from being dumped a second time on exit when the
+     application already wrote out the profile using __gcov_dump().  */
+  if (gcov_dump_complete)
+    return;
+
+  crc32 = gcov_exit_compute_summary (&this_prg);
+
+  allocate_filename_struct (&gf);
+#if !GCOV_LOCKED
+  memset (&all_prg, 0, sizeof (all_prg));
+#endif
+
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg, &this_prg);
+
+      /* The IS_PRIMARY field is overloaded to indicate if this module
+         is FDO/LIPO.  */
+      dump_module_info |= gi_ptr->mod_info->is_primary;
+    }
+
+  if (dump_module_info)
+    gcov_dump_module_info (&gf);
+
+  free (gi_filename);
+}
+
+/* Reset all counters to zero.  */
+
+void
+gcov_clear (void)
+{
+  const struct gcov_info *gi_ptr;
+
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      unsigned f_ix;
+
+      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+	{
+	  unsigned t_ix;
+	  const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+
+	  if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+	    continue;
+	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+	  for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+	    {
+	      if (!gi_ptr->merge[t_ix])
+		continue;
+
+	      memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+	      ci_ptr++;
+	    }
+	}
+    }
+}
+
+/* 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 (!gcov_sampling_period_initialized)
+    {
+      const char* env_value_str = getenv ("GCOV_SAMPLING_PERIOD");
+      if (env_value_str)
+        {
+          int env_value_int = atoi(env_value_str);
+          if (env_value_int >= 1)
+            __gcov_sampling_period = env_value_int;
+        }
+      gcov_sampling_period_initialized = 1;
+    }
+
+  if (!info->version || !info->n_functions)
+    return;
+
+  if (gcov_version (info, info->version, 0))
+    {
+      size_t filename_length = strlen (info->filename);
+
+      /* Refresh the longest file name information.  */
+      if (filename_length > gcov_max_filename)
+        gcov_max_filename = filename_length;
+
+      /* Assign the module ID (starting at 1).  */
+      info->mod_info->ident = (++gcov_cur_module_id);
+      gcc_assert (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (GEN_FUNC_GLOBAL_ID (
+                                                       info->mod_info->ident, 0))
+                  == info->mod_info->ident);
+
+      if (!__gcov_list)
+        {
+          atexit (gcov_exit);
+        }
+
+      info->next = __gcov_list;
+      __gcov_list = info;
+    }
+  info->version = 0;
+}
+
+/* This function returns the size of gcda file to be written. Note
+   the size is in units of gcov_type.  */
+
+GCOV_LINKAGE unsigned gcov_gcda_file_size (const struct gcov_info *,
+                                           const struct gcov_summary *);
+
+GCOV_LINKAGE unsigned
+gcov_gcda_file_size (const struct gcov_info *gi_ptr,
+                     const struct gcov_summary *sum)
+{
+  unsigned size;
+  const struct gcov_fn_info *fi_ptr;
+  unsigned f_ix, t_ix, h_ix, h_cnt = 0;
+  unsigned n_counts;
+  const struct gcov_ctr_info *ci_ptr;
+  const struct gcov_ctr_summary *csum;
+
+  /* GCOV_DATA_MAGIC, GCOV_VERSION and time_stamp.  */
+  size = 3;
+
+  /* Program summary, which depends on the number of non-zero
+      histogram entries.  */
+   csum = &sum->ctrs[GCOV_COUNTER_ARCS];
+   for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
+     {
+       if (csum->histogram[h_ix].num_counters > 0)
+         h_cnt++;
+     }
+   size += 2 + GCOV_TAG_SUMMARY_LENGTH(h_cnt);
+
+  /* size for each function.  */
+  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+    {
+      fi_ptr = gi_ptr->functions[f_ix];
+
+      size += 2 /* tag_length itself */
+              + GCOV_TAG_FUNCTION_LENGTH; /* ident, lineno_cksum, cfg_cksm */
+
+      ci_ptr = fi_ptr->ctrs;
+      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
+        {
+          if (!gi_ptr->merge[t_ix])
+            continue;
+
+          n_counts = ci_ptr->num;
+          size += 2 + GCOV_TAG_COUNTER_LENGTH (n_counts);
+          ci_ptr++;
+        }
+    }
+
+  size += 1;
+
+  return size*4;
+}
+
+#endif /* L_gcov */
+#endif /* inhibit_libc */
Index: libgcc/libgcov-merge.c
===================================================================
--- libgcc/libgcov-merge.c	(revision 0)
+++ libgcc/libgcov-merge.c	(revision 0)
@@ -0,0 +1,272 @@ 
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2013 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 "libgcov.h"
+
+#if defined(inhibit_libc)
+/* If libc and its header files are not available, provide dummy functions.  */
+
+#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
+
+#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_dc
+
+/* Returns 1 if the function global id GID is not valid.  */
+
+static int
+__gcov_is_gid_insane (gcov_type gid)
+{
+  if (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (gid) == 0
+      || EXTRACT_FUNC_ID_FROM_GLOBAL_ID (gid) == 0)
+    return 1;
+  return 0;
+}
+
+/* The profile merging function used for merging direct call counts
+   This function is given array COUNTERS of N_COUNTERS old counters and it
+   reads the same number of counters from the gcov file.  */
+
+void
+__gcov_merge_dc (gcov_type *counters, unsigned n_counters)
+{
+  unsigned i;
+
+  gcc_assert (!(n_counters % 2));
+  for (i = 0; i < n_counters; i += 2)
+    {
+      gcov_type global_id = gcov_read_counter ();
+      gcov_type call_count = gcov_read_counter ();
+
+      /* Note that global id counter may never have been set if no calls were
+	 made from this call-site.  */
+      if (counters[i] && global_id)
+        {
+          /* TODO race condition requires us do the following correction.  */
+          if (__gcov_is_gid_insane (counters[i]))
+            counters[i] = global_id;
+          else if (__gcov_is_gid_insane (global_id))
+            global_id = counters[i];
+
+          gcc_assert (counters[i] == global_id);
+        }
+      else if (global_id)
+	counters[i] = global_id;
+
+      counters[i + 1] += call_count;
+
+      /* Reset. */
+      if (__gcov_is_gid_insane (counters[i]))
+        counters[i] = counters[i + 1] = 0;
+
+      /* Assert that the invariant (global_id == 0) <==> (call_count == 0)
+	 holds true after merging.  */
+      if (counters[i] == 0)
+        counters[i+1] = 0;
+      if (counters[i + 1] == 0)
+        counters[i] = 0;
+    }
+}
+#endif
+
+#ifdef L_gcov_merge_icall_topn
+/* The profile merging function used for merging indirect call counts
+   This function is given array COUNTERS of N_COUNTERS old counters and it
+   reads the same number of counters from the gcov file.  */
+
+void
+__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
+{
+  unsigned i, j, k, m;
+
+  gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
+  for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
+    {
+      gcov_type *value_array = &counters[i + 1];
+      unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1);
+      gcov_type *tmp_array
+          = (gcov_type *) alloca (tmp_size * sizeof (gcov_type));
+
+      for (j = 0; j < tmp_size; j++)
+        tmp_array[j] = 0;
+
+      for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
+        {
+          tmp_array[j] = value_array[j];
+          tmp_array[j + 1] = value_array [j + 1];
+        }
+
+      /* Skip the number_of_eviction entry.  */
+      gcov_read_counter ();
+      for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
+        {
+          int found = 0;
+          gcov_type global_id = gcov_read_counter ();
+          gcov_type call_count = gcov_read_counter ();
+          for (m = 0; m < j; m += 2)
+            {
+              if (tmp_array[m] == global_id)
+                {
+                  found = 1;
+                  tmp_array[m + 1] += call_count;
+                  break;
+                }
+            }
+          if (!found)
+            {
+              tmp_array[j] = global_id;
+              tmp_array[j + 1] = call_count;
+              j += 2;
+            }
+        }
+      /* Now sort the temp array */
+      gcov_sort_n_vals (tmp_array, j);
+
+      /* Now copy back the top half of the temp array */
+      for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
+        {
+          value_array[k] = tmp_array[k];
+          value_array[k + 1] = tmp_array[k + 1];
+        }
+    }
+}
+#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 */
+#endif /* inhibit_libc */
Index: libgcc/dyn-ipa.c
===================================================================
--- libgcc/dyn-ipa.c	(revision 206637)
+++ libgcc/dyn-ipa.c	(working copy)
@@ -24,24 +24,8 @@  a copy of the GCC Runtime Library Exception along
 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"
+#include "libgcov.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>
-#include <stdlib.h>
-#define IN_LIBGCOV 1
-#if defined(L_gcov)
-#define GCOV_LINKAGE /* nothing */
-#endif
-#endif
-#include "gcov-io.h"
-
 struct dyn_pointer_set;
 
 #define XNEWVEC(type,ne) (type *)malloc(sizeof(type) * (ne))
@@ -232,7 +216,7 @@  init_dyn_cgraph_node (struct dyn_cgraph_node *node
   node->visited = 0;
 }
 
-/* Return module_id. FUNC_GUID is the global unique id.  
+/* Return module_id. FUNC_GUID is the global unique id.
    This id is 1 based. 0 is the invalid id.  */
 
 static inline gcov_unsigned_t
@@ -317,8 +301,6 @@  get_module_info (gcov_unsigned_t module_id)
   return the_dyn_call_graph.modules[module_id - 1];
 }
 
-struct gcov_info *__gcov_list ATTRIBUTE_HIDDEN;
-
 static inline unsigned
 cgraph_node_get_key (const void *p)
 {
@@ -371,6 +353,9 @@  get_imported_modus (unsigned module_ident)
   return p;
 }
 
+/* Defined in libgcov-driver.c.  */
+extern struct gcov_info *get_gcov_list (void);
+
 /* Initialize dynamic call graph.  */
 
 static void
@@ -380,6 +365,7 @@  init_dyn_call_graph (void)
   struct gcov_info *gi_ptr;
   const char *env_str;
   int do_dump = (do_cgraph_dump () != 0);
+  struct gcov_info *gcov_list = get_gcov_list ();
 
   the_dyn_call_graph.call_graph_nodes = 0;
   the_dyn_call_graph.modules = 0;
@@ -390,7 +376,7 @@  init_dyn_call_graph (void)
   flag_weak_inclusion = __gcov_lipo_weak_inclusion;
   mem_threshold = __gcov_lipo_max_mem * 1.25;
 
-  gi_ptr = __gcov_list;
+  gi_ptr = gcov_list;
 
   for (; gi_ptr; gi_ptr = gi_ptr->next)
     num_modules++;
@@ -408,7 +394,7 @@  init_dyn_call_graph (void)
   the_dyn_call_graph.call_graph_nodes
     = XNEWVEC (struct dyn_pointer_set *, num_modules);
 
-  gi_ptr = __gcov_list;
+  gi_ptr = gcov_list;
 
   if ((env_str = getenv ("GCOV_DYN_ALG")))
     {
@@ -421,7 +407,7 @@  init_dyn_call_graph (void)
         flag_weak_inclusion = atoi (env_str);
 
       if (do_dump)
-	fprintf (stderr, 
+	fprintf (stderr,
             "!!!! Using ALG=%d merge_edges=%d weak_inclusion=%d. \n",
             flag_alg_mode, flag_modu_merge_edges, flag_weak_inclusion);
     }
@@ -1613,7 +1599,7 @@  modu_graph_process_dyn_cgraph_node (struct dyn_cgr
   while (callees != 0)
     {
       callee = callees->callee;
-      unsigned callee_m_id = 
+      unsigned callee_m_id =
         get_module_ident_from_func_glob_uid (callee->guid);
       if (callee_m_id != m_id)
         {
@@ -1769,7 +1755,7 @@  modu_add_auxiliary (unsigned t_mid, unsigned s_mid
 
 /* Check if inserting the module specified by DATA1 (including
    it's imported list to grouping VALUE, makes the ggc_memory
-   size exceed the memory threshold. 
+   size exceed the memory threshold.
    Return 0 if size is great than the thereshold and 0 otherwise.  */
 
 static int
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in	(revision 206637)
+++ libgcc/Makefile.in	(working copy)
@@ -850,25 +850,35 @@  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_reset _gcov_dump \
-    _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
+LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single _gcov_merge_delta _gcov_merge_ior \
+                _gcov_merge_dc _gcov_merge_icall_topn _gcov_merge_reusedist
+LIBGCOV_PROFILER = _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
     _gcov_indirect_call_profiler _gcov_average_profiler _gcov_ior_profiler \
-    _gcov_indirect_call_profiler _gcov_direct_call_profiler \
-    _gcov_average_profiler _gcov_ior_profiler _gcov_merge_ior _gcov_merge_dc \
-    _gcov_merge_icall_topn _gcov_indirect_call_topn_profiler \
-    _gcov_merge_reusedist
+    _gcov_indirect_call_topn_profiler _gcov_direct_call_profiler
+LIBGCOV_INTERFACE = _gcov_flush _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
+    _gcov_execv _gcov_execvp _gcov_execve _gcov_reset _gcov_dump _gcov_sampling \
+    _gcov_prefix
+LIBGCOV_DRIVER = _gcov 
 
-libgcov-objects = $(patsubst %,%$(objext),$(LIBGCOV))
+libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
+libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER))
+libgcov-interface-objects = $(patsubst %,%$(objext),$(LIBGCOV_INTERFACE))
+libgcov-driver-objects = $(patsubst %,%$(objext),$(LIBGCOV_DRIVER))
+libgcov-objects = $(libgcov-merge-objects) $(libgcov-profiler-objects) \
+                 $(libgcov-interface-objects) $(libgcov-driver-objects)
 
-dyn-ipa.o: %$(objext): $(srcdir)/libgcov.c
-	$(gcc_compile)  -c $(srcdir)/dyn-ipa.c
+dyn-ipa.o: %$(objext): $(srcdir)/dyn-ipa.c $(srcdir)/libgcov.h
+	$(gcc_compile) -c $(srcdir)/dyn-ipa.c
+$(libgcov-merge-objects): %$(objext): $(srcdir)/libgcov-merge.c $(srcdir)/libgcov.h
+	$(gcc_compile) -DL$* -c $(srcdir)/libgcov-merge.c
+$(libgcov-profiler-objects): %$(objext): $(srcdir)/libgcov-profiler.c $(srcdir)/libgcov.h
+	$(gcc_compile) -DL$* -c $(srcdir)/libgcov-profiler.c
+$(libgcov-interface-objects): %$(objext): $(srcdir)/libgcov-interface.c $(srcdir)/libgcov.h
+	$(gcc_compile) -DL$* -c $(srcdir)/libgcov-interface.c
+$(libgcov-driver-objects): %$(objext): $(srcdir)/libgcov-driver.c \
+  $(srcdir)/libgcov-driver-system.c $(srcdir)/libgcov.h
+	$(gcc_compile) -DL$* -c $(srcdir)/libgcov-driver.c
 
-$(libgcov-objects): %$(objext): $(srcdir)/libgcov.c
-	$(gcc_compile) -DL$* -c $(srcdir)/libgcov.c
-
 # Static libraries.
 libgcc.a: $(libgcc-objects)
 libgcov.a: $(libgcov-objects) dyn-ipa$(objext)
@@ -1094,10 +1104,14 @@  install-leaf: $(install-shared) $(install-libunwin
 	  cp ../../gcc/gcov-iov.h $$gcov_src_dest;		\
 	  cp $(srcdir)/../gcc/gcov-io.h $$gcov_src_dest;	\
 	  cp $(srcdir)/../gcc/gcov-io.c $$gcov_src_dest;	\
-	  cp $(srcdir)/libgcov.c $$gcov_src_dest;		\
+	  cp $(srcdir)/libgcov-driver.c $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov-merge.c $$gcov_src_dest;		\
+	  cp $(srcdir)/libgcov.h $$gcov_src_dest;		\
 	  chmod 644 $$gcov_src_dest/gcov-iov.h			\
 	  $$gcov_src_dest/gcov-io.h $$gcov_src_dest/gcov-io.c	\
-	  $$gcov_src_dest/libgcov.c;				\
+ 	  $$gcov_src_dest/libgcov.h				\
+	  $$gcov_src_dest/libgcov-merge.c			\
+	  $$gcov_src_dest/libgcov-driver.c;			\
 	fi
 
 install: install-leaf install-unwind_h
Index: gcc/gcov-io.c
===================================================================
--- gcc/gcov-io.c	(revision 206637)
+++ gcc/gcov-io.c	(working copy)
@@ -36,6 +36,58 @@  static const gcov_unsigned_t *gcov_read_words (uns
 static void gcov_allocate (unsigned);
 #endif
 
+/* Optimum number of gcov_unsigned_t's read from or written to disk.  */
+#define GCOV_BLOCK_SIZE (1 << 10)
+
+GCOV_LINKAGE struct gcov_var
+{
+  FILE *file;
+  gcov_position_t start;        /* Position of first byte of block */
+  unsigned offset;              /* Read/write position within the block.  */
+  unsigned length;              /* Read limit in the block.  */
+  unsigned overread;            /* Number of words overread.  */
+  int error;                    /* < 0 overflow, > 0 disk error.  */
+  int mode;                     /* < 0 writing, > 0 reading */
+#if IN_LIBGCOV
+  /* Holds one block plus 4 bytes, thus all coverage reads & writes
+     fit within this buffer and we always can transfer GCOV_BLOCK_SIZE
+     to and from the disk. libgcov never backtracks and only writes 4
+     or 8 byte objects.  */
+  gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1];
+#else
+  int endian;                   /* Swap endianness.  */
+  /* Holds a variable length block, as the compiler can write
+     strings and needs to backtrack.  */
+  size_t alloc;
+  gcov_unsigned_t *buffer;
+#endif
+} gcov_var;
+
+/* Save the current position in the gcov file.  */
+static inline gcov_position_t
+gcov_position (void)
+{
+  return gcov_var.start + gcov_var.offset;
+}
+
+/* Return nonzero if the error flag is set.  */
+static inline int
+gcov_is_error (void)
+{
+  return gcov_var.file ? gcov_var.error : 1;
+}
+
+/* Move to beginning of file and initialize for writing.  */
+static inline void
+gcov_rewrite (void)
+{
+  gcc_assert (gcov_var.mode > 0);
+  gcov_var.mode = -1;
+  gcov_var.start = 0;
+  gcov_var.offset = 0;
+  fseek (gcov_var.file, 0L, SEEK_SET);
+}
+
 static inline gcov_unsigned_t from_file (gcov_unsigned_t value)
 {
 #if !IN_LIBGCOV
Index: gcc/gcov-io.h
===================================================================
--- gcc/gcov-io.h	(revision 206637)
+++ gcc/gcov-io.h	(working copy)
@@ -164,84 +164,7 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #ifndef GCC_GCOV_IO_H
 #define GCC_GCOV_IO_H
 
-#if IN_LIBGCOV
-
-#undef FUNC_ID_WIDTH
-#undef FUNC_ID_MASK
-/* About the target */
-
-#if BITS_PER_UNIT == 8
-typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
-typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
-#if LONG_LONG_TYPE_SIZE > 32
-typedef signed gcov_type __attribute__ ((mode (DI)));
-#define FUNC_ID_WIDTH 32
-#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
-#else
-typedef signed gcov_type __attribute__ ((mode (SI)));
-#define FUNC_ID_WIDTH 16
-#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
-#endif
-#else   /* BITS_PER_UNIT != 8  */
-#if BITS_PER_UNIT == 16
-typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
-typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
-#if LONG_LONG_TYPE_SIZE > 32
-typedef signed gcov_type __attribute__ ((mode (SI)));
-#define FUNC_ID_WIDTH 32
-#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
-#else
-typedef signed gcov_type __attribute__ ((mode (HI)));
-#define FUNC_ID_WIDTH 16
-#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
-#endif
-#else  /* BITS_PER_UNIT != 16  */
-typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
-typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
-#if LONG_LONG_TYPE_SIZE > 32
-typedef signed gcov_type __attribute__ ((mode (HI)));
-#define FUNC_ID_WIDTH 32
-#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
-#else
-typedef signed gcov_type __attribute__ ((mode (QI)));
-#define FUNC_ID_WIDTH 16
-#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
-typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
-#endif
-#endif /* BITS_PER_UNIT == 16  */ 
-
-#endif  /* BITS_PER_UNIT == 8  */
-
-#if LONG_LONG_TYPE_SIZE > 32
-#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_8
-#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_8
-#else
-#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_4
-#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_4
-#endif
-
-#undef EXTRACT_MODULE_ID_FROM_GLOBAL_ID
-#undef EXTRACT_FUNC_ID_FROM_GLOBAL_ID
-#undef GEN_FUNC_GLOBAL_ID
-#define EXTRACT_MODULE_ID_FROM_GLOBAL_ID(gid) \
-                (gcov_unsigned_t)(((gid) >> FUNC_ID_WIDTH) & FUNC_ID_MASK)
-#define EXTRACT_FUNC_ID_FROM_GLOBAL_ID(gid) \
-                (gcov_unsigned_t)((gid) & FUNC_ID_MASK)
-#define GEN_FUNC_GLOBAL_ID(m,f) ((((gcov_type) (m)) << FUNC_ID_WIDTH) | (f))
-
-
-#if defined (TARGET_POSIX_IO)
-#define GCOV_LOCKED 1
-#else
-#define GCOV_LOCKED 0
-#endif
-
-#else /* !IN_LIBGCOV */
+#ifndef IN_LIBGCOV
 /* About the host */
 
 typedef unsigned gcov_unsigned_t;
@@ -284,52 +207,10 @@  typedef unsigned HOST_WIDEST_INT gcov_type_unsigne
 #define GCOV_LOCKED 0
 #endif
 
-#endif /* !IN_LIBGCOV */
-
-/* In gcov we want function linkage to be static.  In the compiler we want
-   it extern, so that they can be accessed from elsewhere.  In libgcov we
-   need these functions to be extern, so prefix them with __gcov.  In
-   libgcov they must also be hidden so that the instance in the executable
-   is not also used in a DSO.  */
-#if IN_LIBGCOV
-
-#include "tconfig.h"
-
-#define gcov_var __gcov_var
-#define gcov_open __gcov_open
-#define gcov_close __gcov_close
-#define gcov_write_tag_length __gcov_write_tag_length
-#define gcov_position __gcov_position
-#define gcov_seek __gcov_seek
-#define gcov_rewrite __gcov_rewrite
-#define gcov_truncate __gcov_truncate
-#define gcov_is_error __gcov_is_error
-#define gcov_write_unsigned __gcov_write_unsigned
-#define gcov_write_counter __gcov_write_counter
-#define gcov_write_summary __gcov_write_summary
-#define gcov_write_module_info __gcov_write_module_info
-#define gcov_read_unsigned __gcov_read_unsigned
-#define gcov_read_counter __gcov_read_counter
-#define gcov_read_summary __gcov_read_summary
-#define gcov_read_module_info __gcov_read_module_info
-#define gcov_sort_n_vals __gcov_sort_n_vals
-
-/* Poison these, so they don't accidentally slip in.  */
-#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
-#pragma GCC poison gcov_read_string gcov_sync gcov_time gcov_magic
-
-#ifdef HAVE_GAS_HIDDEN
-#define ATTRIBUTE_HIDDEN  __attribute__ ((__visibility__ ("hidden")))
-#else
 #define ATTRIBUTE_HIDDEN
-#endif
 
-#else
+#endif /* !IN_LIBGCOV */
 
-#define ATTRIBUTE_HIDDEN
-
-#endif
-
 #ifndef GCOV_LINKAGE
 #define GCOV_LINKAGE extern
 #endif
@@ -527,7 +408,7 @@  struct gcov_module_info
 				 (2) means IS_PRIMARY in persistent file or
 				     memory copy used in profile-use.  */
   gcov_unsigned_t flags;      /* bit 0: is_exported,
-                                 bit 1: need to include all the auxiliary 
+                                 bit 1: need to include all the auxiliary
                                  modules in use compilation.  */
   gcov_unsigned_t lang; /* lower 16 bits encode the language, and the upper
 			   16 bits enocde other attributes, such as whether
@@ -555,148 +436,8 @@  extern unsigned primary_module_id;
    && !((module_infos[0]->lang & GCOV_MODULE_ASM_STMTS)			\
 	&& flag_ripa_disallow_asm_modules))
 
-/* Structures embedded in coveraged program.  The structures generated
-   by write_profile must match these.  */
+#if !defined(inhibit_libc)
 
-#if IN_LIBGCOV
-/* Information about counters for a single function.  */
-struct gcov_ctr_info
-{
-  gcov_unsigned_t num;		/* number of counters.  */
-  gcov_type *values;		/* their values.  */
-};
-
-/* Information about a single function.  This uses the trailing array
-   idiom. The number of counters is determined from the merge pointer
-   array in gcov_info.  The key is used to detect which of a set of
-   comdat functions was selected -- it points to the gcov_info object
-   of the object file containing the selected comdat function.  */
-
-struct gcov_fn_info
-{
-  const struct gcov_info *key;		/* comdat key */
-  gcov_unsigned_t ident;		/* unique ident of function */
-  gcov_unsigned_t lineno_checksum;	/* function lineo_checksum */
-  gcov_unsigned_t cfg_checksum;	/* function cfg checksum */
-  struct gcov_ctr_info ctrs[0];		/* instrumented counters */
-};
-
-/* Type of function used to merge counters.  */
-typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
-
-/* Information about a single object file.  */
-struct gcov_info
-{
-  gcov_unsigned_t version;	/* expected version number */
-  struct gcov_module_info *mod_info; /* addtional module info.  */
-  struct gcov_info *next;	/* link to next, used by libgcov */
-
-  gcov_unsigned_t stamp;	/* uniquifying time stamp */
-  const char *filename;		/* output file name */
-  gcov_unsigned_t eof_pos;      /* end position of profile data */
-  gcov_merge_fn merge[GCOV_COUNTERS];  /* merge functions (null for
-					  unused) */
-  
-  unsigned n_functions;		/* number of functions */
-  const struct gcov_fn_info *const *functions; /* pointer to pointers
-					          to function information  */
-};
-
-/* Information about a single imported module.  */
-struct dyn_imp_mod
-{
-  const struct gcov_info *imp_mod;
-  double weight;
-};
-
-/* Register a new object file module.  */
-extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
-
-/* Set sampling rate to RATE.  */
-extern void __gcov_set_sampling_rate (unsigned int rate);
-
-/* Called before fork, to avoid double counting.  */
-extern void __gcov_flush (void) ATTRIBUTE_HIDDEN;
-
-/* Function to reset all counters to 0.  */
-extern void __gcov_reset (void);
-
-/* Function to enable early write of profile information so far.  */
-extern void __gcov_dump (void);
-
-/* The merge function that just sums the counters.  */
-extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The merge function to choose the most common value.  */
-extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The merge function to choose the most common difference between
-   consecutive values.  */
-extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The merge function that just ors the counters together.  */
-extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The merge function used for direct call counters.  */
-extern void __gcov_merge_dc (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The merge function used for indirect call counters.  */
-extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
-/* The profiler functions.  */
-extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
-extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
-extern void __gcov_one_value_profiler (gcov_type *, gcov_type);
-extern void __gcov_indirect_call_profiler (gcov_type *, gcov_type, void *, void *);
-extern void __gcov_indirect_call_topn_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
-extern void __gcov_direct_call_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
-extern void __gcov_average_profiler (gcov_type *, gcov_type);
-extern void __gcov_ior_profiler (gcov_type *, gcov_type);
-extern void __gcov_sort_n_vals (gcov_type *value_array, int n);
-
-#ifndef inhibit_libc
-/* The wrappers around some library functions..  */
-extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
-extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN;
-extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN;
-extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN;
-extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN;
-extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
-extern int __gcov_execve (const char *, char  *const [], char *const [])
-  ATTRIBUTE_HIDDEN;
-#endif
-
-#endif /* IN_LIBGCOV */
-
-#if IN_LIBGCOV >= 0
-
-/* Optimum number of gcov_unsigned_t's read from or written to disk.  */
-#define GCOV_BLOCK_SIZE (1 << 10)
-
-GCOV_LINKAGE struct gcov_var
-{
-  FILE *file;
-  gcov_position_t start;	/* Position of first byte of block */
-  unsigned offset;		/* Read/write position within the block.  */
-  unsigned length;		/* Read limit in the block.  */
-  unsigned overread;		/* Number of words overread.  */
-  int error;			/* < 0 overflow, > 0 disk error.  */
-  int mode;	                /* < 0 writing, > 0 reading */
-#if IN_LIBGCOV
-  /* Holds one block plus 4 bytes, thus all coverage reads & writes
-     fit within this buffer and we always can transfer GCOV_BLOCK_SIZE
-     to and from the disk. libgcov never backtracks and only writes 4
-     or 8 byte objects.  */
-  gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1];
-#else
-  int endian;			/* Swap endianness.  */
-  /* Holds a variable length block, as the compiler can write
-     strings and needs to backtrack.  */
-  size_t alloc;
-  gcov_unsigned_t *buffer;
-#endif
-} gcov_var ATTRIBUTE_HIDDEN;
-
 /* Functions for reading and writing gcov files. In libgcov you can
    open the file for reading then writing. Elsewhere you can open the
    file either for reading or for writing. When reading a file you may
@@ -706,50 +447,25 @@  extern unsigned primary_module_id;
    you use the functions for reading, then gcov_rewrite then the
    functions for writing.  Your file may become corrupted if you break
    these invariants.  */
-#if IN_LIBGCOV
-GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
-#else
+#if !IN_LIBGCOV
 GCOV_LINKAGE int gcov_open (const char */*name*/, int /*direction*/);
 GCOV_LINKAGE int gcov_magic (gcov_unsigned_t, gcov_unsigned_t);
 #endif
-GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN;
 
 /* Available everywhere.  */
-static gcov_position_t gcov_position (void);
-static int gcov_is_error (void);
-
+GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE const char *gcov_read_string (void);
+GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/,
+			     gcov_unsigned_t /*length */);
+
 #if !IN_LIBGCOV && IN_GCOV != 1
 GCOV_LINKAGE void gcov_read_module_info (struct gcov_module_info *mod_info,
 					 gcov_unsigned_t len) ATTRIBUTE_HIDDEN;
 #endif
 
-#if IN_LIBGCOV
-/* Available only in libgcov */
-GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN;
-GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t)
-    ATTRIBUTE_HIDDEN;
-GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
-				      const struct gcov_summary *)
-    ATTRIBUTE_HIDDEN;
-
-GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info)
-    ATTRIBUTE_HIDDEN;
-GCOV_LINKAGE const struct dyn_imp_mod **
-gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len)
-    ATTRIBUTE_HIDDEN;
-static void gcov_rewrite (void);
-GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
-GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN;
-#else
-/* Available outside libgcov */
-GCOV_LINKAGE const char *gcov_read_string (void);
-GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/,
-			     gcov_unsigned_t /*length */);
-#endif
-
 #if !IN_GCOV
 /* Available outside gcov */
 GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN;
@@ -790,36 +506,6 @@  GCOV_LINKAGE void compute_working_sets (const stru
 GCOV_LINKAGE time_t gcov_time (void);
 #endif
 
-/* Save the current position in the gcov file.  */
+#endif /* !inhibit_libc  */
 
-static inline gcov_position_t
-gcov_position (void)
-{
-  return gcov_var.start + gcov_var.offset;
-}
-
-/* Return nonzero if the error flag is set.  */
-
-static inline int
-gcov_is_error (void)
-{
-  return gcov_var.file ? gcov_var.error : 1;
-}
-
-#if IN_LIBGCOV
-/* Move to beginning of file and initialize for writing.  */
-
-static inline void
-gcov_rewrite (void)
-{
-  gcc_assert (gcov_var.mode > 0);
-  gcov_var.mode = -1;
-  gcov_var.start = 0;
-  gcov_var.offset = 0;
-  fseek (gcov_var.file, 0L, SEEK_SET);
-}
-#endif
-
-#endif /* IN_LIBGCOV >= 0 */
-
 #endif /* GCC_GCOV_IO_H */