/* Routines required for instrumenting a program. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989-2013 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2017 Free Software Foundation, Inc.
This file is part of GCC.
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 "libgcov.h"
#include "gthr.h"
-#if defined(inhibit_libc)
-#define IN_LIBGCOV (-1)
-#else
-#define IN_LIBGCOV 1
-#endif
-#include "gcov-io.h"
-
#if defined(inhibit_libc)
#ifdef L_gcov_flush
#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;
+/* Some functions we want to bind in this dynamic object, but have an
+ overridable global alias. Unfortunately not all targets support
+ aliases, so we just have a forwarding function. That'll be tail
+ called, so the cost is a single jump instruction.*/
-#ifdef L_gcov_flush
+#define ALIAS_void_fn(src,dst) \
+ void dst (void) \
+ { src (); }
+extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
+extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
+
+#ifdef L_gcov_flush
#ifdef __GTHREAD_MUTEX_INIT
-ATTRIBUTE_HIDDEN __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
+__gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
#define init_mx_once()
#else
-__gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
+__gthread_mutex_t __gcov_flush_mx;
static void
init_mx (void)
{
__GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
}
+
static void
init_mx_once (void)
{
init_mx_once ();
__gthread_mutex_lock (&__gcov_flush_mx);
- gcov_exit ();
- gcov_clear ();
+ __gcov_dump_int ();
+ __gcov_reset_int ();
__gthread_mutex_unlock (&__gcov_flush_mx);
}
#ifdef L_gcov_reset
+/* Reset all counters to zero. */
+
+static void
+gcov_clear (const struct gcov_info *list)
+{
+ const struct gcov_info *gi_ptr;
+
+ for (gi_ptr = 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++;
+ }
+ }
+ }
+}
+
/* 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_reset_int (void)
{
- gcov_clear ();
- /* Re-enable dumping to support collecting profile in multiple regions
- of interest. */
- reset_gcov_dump_complete ();
+ struct gcov_root *root;
+
+ /* If we're compatible with the master, iterate over everything,
+ otherise just do us. */
+ for (root = __gcov_master.version == GCOV_VERSION
+ ? __gcov_master.root : &__gcov_root; root; root = root->next)
+ {
+ gcov_clear (root->list);
+ root->dumped = 0;
+ }
}
+ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
+
#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_dump_int (void)
{
- gcov_exit ();
- /* Prevent profile from being dumped a second time on application exit. */
- set_gcov_dump_complete ();
+ struct gcov_root *root;
+
+ /* If we're compatible with the master, iterate over everything,
+ otherise just do us. */
+ for (root = __gcov_master.version == GCOV_VERSION
+ ? __gcov_master.root : &__gcov_root; root; root = root->next)
+ __gcov_dump_one (root);
}
-#endif /* L_gcov_dump */
+ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
+#endif /* L_gcov_dump */
#ifdef L_gcov_fork
/* A wrapper for the fork function. Flushes the accumulated profiling data, so
__gcov_fork (void)
{
pid_t pid;
- extern __gthread_mutex_t __gcov_flush_mx;
__gcov_flush ();
pid = fork ();
if (pid == 0)
#endif
#ifdef L_gcov_execl
-/* A wrapper for the execl function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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, ...)
#endif
#ifdef L_gcov_execlp
-/* A wrapper for the execlp function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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, ...)
#endif
#ifdef L_gcov_execle
-/* A wrapper for the execle function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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, ...)
#endif
#ifdef L_gcov_execv
-/* A wrapper for the execv function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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[])
#endif
#ifdef L_gcov_execvp
-/* A wrapper for the execvp function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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[])
#endif
#ifdef L_gcov_execve
-/* A wrapper for the execve function. Flushes the accumulated profiling data, so
- that they are not lost. */
+/* 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[])