123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /* Routines required for instrumenting a program. */
- /* Compile this one with gcc. */
- /* Copyright (C) 1989-2015 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)
- #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
- /* 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.*/
- #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
- __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
- #define init_mx_once()
- #else
- __gthread_mutex_t __gcov_flush_mx;
- 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_dump_int ();
- __gcov_reset_int ();
- __gthread_mutex_unlock (&__gcov_flush_mx);
- }
- #endif /* L_gcov_flush */
- #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_int (void)
- {
- 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_int (void)
- {
- 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);
- }
- 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
- that they are not counted twice. */
- pid_t
- __gcov_fork (void)
- {
- pid_t pid;
- __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 */
|