11debfc3dSmrg /* Routines required for instrumenting a program. */
21debfc3dSmrg /* Compile this one with gcc. */
3*8feb0f0bSmrg /* Copyright (C) 1989-2020 Free Software Foundation, Inc.
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg
171debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
181debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
191debfc3dSmrg 3.1, as published by the Free Software Foundation.
201debfc3dSmrg
211debfc3dSmrg You should have received a copy of the GNU General Public License and
221debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
231debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
241debfc3dSmrg <http://www.gnu.org/licenses/>. */
251debfc3dSmrg
261debfc3dSmrg #include "libgcov.h"
271debfc3dSmrg #include "gthr.h"
281debfc3dSmrg
291debfc3dSmrg #if defined(inhibit_libc)
301debfc3dSmrg
311debfc3dSmrg #ifdef L_gcov_flush
__gcov_flush(void)321debfc3dSmrg void __gcov_flush (void) {}
331debfc3dSmrg #endif
341debfc3dSmrg
351debfc3dSmrg #ifdef L_gcov_reset
__gcov_reset(void)361debfc3dSmrg void __gcov_reset (void) {}
371debfc3dSmrg #endif
381debfc3dSmrg
391debfc3dSmrg #ifdef L_gcov_dump
__gcov_dump(void)401debfc3dSmrg void __gcov_dump (void) {}
411debfc3dSmrg #endif
421debfc3dSmrg
431debfc3dSmrg #else
441debfc3dSmrg
451debfc3dSmrg /* Some functions we want to bind in this dynamic object, but have an
461debfc3dSmrg overridable global alias. Unfortunately not all targets support
471debfc3dSmrg aliases, so we just have a forwarding function. That'll be tail
481debfc3dSmrg called, so the cost is a single jump instruction.*/
491debfc3dSmrg
501debfc3dSmrg #define ALIAS_void_fn(src,dst) \
511debfc3dSmrg void dst (void) \
521debfc3dSmrg { src (); }
531debfc3dSmrg
541debfc3dSmrg extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
551debfc3dSmrg
561debfc3dSmrg #ifdef L_gcov_flush
571debfc3dSmrg #ifdef __GTHREAD_MUTEX_INIT
581debfc3dSmrg __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
591debfc3dSmrg #define init_mx_once()
601debfc3dSmrg #else
611debfc3dSmrg __gthread_mutex_t __gcov_flush_mx;
621debfc3dSmrg
631debfc3dSmrg static void
init_mx(void)641debfc3dSmrg init_mx (void)
651debfc3dSmrg {
661debfc3dSmrg __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
671debfc3dSmrg }
681debfc3dSmrg
691debfc3dSmrg static void
init_mx_once(void)701debfc3dSmrg init_mx_once (void)
711debfc3dSmrg {
721debfc3dSmrg static __gthread_once_t once = __GTHREAD_ONCE_INIT;
731debfc3dSmrg __gthread_once (&once, init_mx);
741debfc3dSmrg }
751debfc3dSmrg #endif
761debfc3dSmrg
771debfc3dSmrg /* Called before fork or exec - write out profile information gathered so
781debfc3dSmrg far and reset it to zero. This avoids duplication or loss of the
791debfc3dSmrg profile information gathered so far. */
801debfc3dSmrg
811debfc3dSmrg void
__gcov_flush(void)821debfc3dSmrg __gcov_flush (void)
831debfc3dSmrg {
841debfc3dSmrg init_mx_once ();
851debfc3dSmrg __gthread_mutex_lock (&__gcov_flush_mx);
861debfc3dSmrg
871debfc3dSmrg __gcov_dump_int ();
881debfc3dSmrg __gcov_reset_int ();
891debfc3dSmrg
901debfc3dSmrg __gthread_mutex_unlock (&__gcov_flush_mx);
911debfc3dSmrg }
921debfc3dSmrg
931debfc3dSmrg #endif /* L_gcov_flush */
941debfc3dSmrg
951debfc3dSmrg #ifdef L_gcov_reset
961debfc3dSmrg
971debfc3dSmrg /* Reset all counters to zero. */
981debfc3dSmrg
991debfc3dSmrg static void
gcov_clear(const struct gcov_info * list)1001debfc3dSmrg gcov_clear (const struct gcov_info *list)
1011debfc3dSmrg {
1021debfc3dSmrg const struct gcov_info *gi_ptr;
1031debfc3dSmrg
1041debfc3dSmrg for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
1051debfc3dSmrg {
1061debfc3dSmrg unsigned f_ix;
1071debfc3dSmrg
1081debfc3dSmrg for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1091debfc3dSmrg {
1101debfc3dSmrg unsigned t_ix;
1111debfc3dSmrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
1121debfc3dSmrg
1131debfc3dSmrg if (!gfi_ptr || gfi_ptr->key != gi_ptr)
1141debfc3dSmrg continue;
1151debfc3dSmrg const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1161debfc3dSmrg for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
1171debfc3dSmrg {
1181debfc3dSmrg if (!gi_ptr->merge[t_ix])
1191debfc3dSmrg continue;
1201debfc3dSmrg
1211debfc3dSmrg memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
1221debfc3dSmrg ci_ptr++;
1231debfc3dSmrg }
1241debfc3dSmrg }
1251debfc3dSmrg }
1261debfc3dSmrg }
1271debfc3dSmrg
1281debfc3dSmrg /* Function that can be called from application to reset counters to zero,
1291debfc3dSmrg in order to collect profile in region of interest. */
1301debfc3dSmrg
1311debfc3dSmrg void
__gcov_reset_int(void)1321debfc3dSmrg __gcov_reset_int (void)
1331debfc3dSmrg {
1341debfc3dSmrg struct gcov_root *root;
1351debfc3dSmrg
1361debfc3dSmrg /* If we're compatible with the master, iterate over everything,
1371debfc3dSmrg otherise just do us. */
1381debfc3dSmrg for (root = __gcov_master.version == GCOV_VERSION
1391debfc3dSmrg ? __gcov_master.root : &__gcov_root; root; root = root->next)
1401debfc3dSmrg {
1411debfc3dSmrg gcov_clear (root->list);
1421debfc3dSmrg root->dumped = 0;
1431debfc3dSmrg }
1441debfc3dSmrg }
1451debfc3dSmrg
1461debfc3dSmrg ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
1471debfc3dSmrg
1481debfc3dSmrg #endif /* L_gcov_reset */
1491debfc3dSmrg
1501debfc3dSmrg #ifdef L_gcov_dump
1511debfc3dSmrg /* Function that can be called from application to write profile collected
1521debfc3dSmrg so far, in order to collect profile in region of interest. */
1531debfc3dSmrg
1541debfc3dSmrg void
__gcov_dump_int(void)1551debfc3dSmrg __gcov_dump_int (void)
1561debfc3dSmrg {
1571debfc3dSmrg struct gcov_root *root;
1581debfc3dSmrg
1591debfc3dSmrg /* If we're compatible with the master, iterate over everything,
1601debfc3dSmrg otherise just do us. */
1611debfc3dSmrg for (root = __gcov_master.version == GCOV_VERSION
1621debfc3dSmrg ? __gcov_master.root : &__gcov_root; root; root = root->next)
1631debfc3dSmrg __gcov_dump_one (root);
1641debfc3dSmrg }
1651debfc3dSmrg
1661debfc3dSmrg ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
1671debfc3dSmrg
1681debfc3dSmrg #endif /* L_gcov_dump */
1691debfc3dSmrg
1701debfc3dSmrg #ifdef L_gcov_fork
1711debfc3dSmrg /* A wrapper for the fork function. Flushes the accumulated profiling data, so
1721debfc3dSmrg that they are not counted twice. */
1731debfc3dSmrg
1741debfc3dSmrg pid_t
__gcov_fork(void)1751debfc3dSmrg __gcov_fork (void)
1761debfc3dSmrg {
1771debfc3dSmrg pid_t pid;
1781debfc3dSmrg __gcov_flush ();
1791debfc3dSmrg pid = fork ();
1801debfc3dSmrg if (pid == 0)
1811debfc3dSmrg __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
1821debfc3dSmrg return pid;
1831debfc3dSmrg }
1841debfc3dSmrg #endif
1851debfc3dSmrg
1861debfc3dSmrg #ifdef L_gcov_execl
1871debfc3dSmrg /* A wrapper for the execl function. Flushes the accumulated
1881debfc3dSmrg profiling data, so that they are not lost. */
1891debfc3dSmrg
1901debfc3dSmrg int
__gcov_execl(const char * path,char * arg,...)1911debfc3dSmrg __gcov_execl (const char *path, char *arg, ...)
1921debfc3dSmrg {
1931debfc3dSmrg va_list ap, aq;
1941debfc3dSmrg unsigned i, length;
1951debfc3dSmrg char **args;
1961debfc3dSmrg
1971debfc3dSmrg __gcov_flush ();
1981debfc3dSmrg
1991debfc3dSmrg va_start (ap, arg);
2001debfc3dSmrg va_copy (aq, ap);
2011debfc3dSmrg
2021debfc3dSmrg length = 2;
2031debfc3dSmrg while (va_arg (ap, char *))
2041debfc3dSmrg length++;
2051debfc3dSmrg va_end (ap);
2061debfc3dSmrg
2071debfc3dSmrg args = (char **) alloca (length * sizeof (void *));
2081debfc3dSmrg args[0] = arg;
2091debfc3dSmrg for (i = 1; i < length; i++)
2101debfc3dSmrg args[i] = va_arg (aq, char *);
2111debfc3dSmrg va_end (aq);
2121debfc3dSmrg
2131debfc3dSmrg return execv (path, args);
2141debfc3dSmrg }
2151debfc3dSmrg #endif
2161debfc3dSmrg
2171debfc3dSmrg #ifdef L_gcov_execlp
2181debfc3dSmrg /* A wrapper for the execlp function. Flushes the accumulated
2191debfc3dSmrg profiling data, so that they are not lost. */
2201debfc3dSmrg
2211debfc3dSmrg int
__gcov_execlp(const char * path,char * arg,...)2221debfc3dSmrg __gcov_execlp (const char *path, char *arg, ...)
2231debfc3dSmrg {
2241debfc3dSmrg va_list ap, aq;
2251debfc3dSmrg unsigned i, length;
2261debfc3dSmrg char **args;
2271debfc3dSmrg
2281debfc3dSmrg __gcov_flush ();
2291debfc3dSmrg
2301debfc3dSmrg va_start (ap, arg);
2311debfc3dSmrg va_copy (aq, ap);
2321debfc3dSmrg
2331debfc3dSmrg length = 2;
2341debfc3dSmrg while (va_arg (ap, char *))
2351debfc3dSmrg length++;
2361debfc3dSmrg va_end (ap);
2371debfc3dSmrg
2381debfc3dSmrg args = (char **) alloca (length * sizeof (void *));
2391debfc3dSmrg args[0] = arg;
2401debfc3dSmrg for (i = 1; i < length; i++)
2411debfc3dSmrg args[i] = va_arg (aq, char *);
2421debfc3dSmrg va_end (aq);
2431debfc3dSmrg
2441debfc3dSmrg return execvp (path, args);
2451debfc3dSmrg }
2461debfc3dSmrg #endif
2471debfc3dSmrg
2481debfc3dSmrg #ifdef L_gcov_execle
2491debfc3dSmrg /* A wrapper for the execle function. Flushes the accumulated
2501debfc3dSmrg profiling data, so that they are not lost. */
2511debfc3dSmrg
2521debfc3dSmrg int
__gcov_execle(const char * path,char * arg,...)2531debfc3dSmrg __gcov_execle (const char *path, char *arg, ...)
2541debfc3dSmrg {
2551debfc3dSmrg va_list ap, aq;
2561debfc3dSmrg unsigned i, length;
2571debfc3dSmrg char **args;
2581debfc3dSmrg char **envp;
2591debfc3dSmrg
2601debfc3dSmrg __gcov_flush ();
2611debfc3dSmrg
2621debfc3dSmrg va_start (ap, arg);
2631debfc3dSmrg va_copy (aq, ap);
2641debfc3dSmrg
2651debfc3dSmrg length = 2;
2661debfc3dSmrg while (va_arg (ap, char *))
2671debfc3dSmrg length++;
2681debfc3dSmrg va_end (ap);
2691debfc3dSmrg
2701debfc3dSmrg args = (char **) alloca (length * sizeof (void *));
2711debfc3dSmrg args[0] = arg;
2721debfc3dSmrg for (i = 1; i < length; i++)
2731debfc3dSmrg args[i] = va_arg (aq, char *);
2741debfc3dSmrg envp = va_arg (aq, char **);
2751debfc3dSmrg va_end (aq);
2761debfc3dSmrg
2771debfc3dSmrg return execve (path, args, envp);
2781debfc3dSmrg }
2791debfc3dSmrg #endif
2801debfc3dSmrg
2811debfc3dSmrg #ifdef L_gcov_execv
2821debfc3dSmrg /* A wrapper for the execv function. Flushes the accumulated
2831debfc3dSmrg profiling data, so that they are not lost. */
2841debfc3dSmrg
2851debfc3dSmrg int
__gcov_execv(const char * path,char * const argv[])2861debfc3dSmrg __gcov_execv (const char *path, char *const argv[])
2871debfc3dSmrg {
2881debfc3dSmrg __gcov_flush ();
2891debfc3dSmrg return execv (path, argv);
2901debfc3dSmrg }
2911debfc3dSmrg #endif
2921debfc3dSmrg
2931debfc3dSmrg #ifdef L_gcov_execvp
2941debfc3dSmrg /* A wrapper for the execvp function. Flushes the accumulated
2951debfc3dSmrg profiling data, so that they are not lost. */
2961debfc3dSmrg
2971debfc3dSmrg int
__gcov_execvp(const char * path,char * const argv[])2981debfc3dSmrg __gcov_execvp (const char *path, char *const argv[])
2991debfc3dSmrg {
3001debfc3dSmrg __gcov_flush ();
3011debfc3dSmrg return execvp (path, argv);
3021debfc3dSmrg }
3031debfc3dSmrg #endif
3041debfc3dSmrg
3051debfc3dSmrg #ifdef L_gcov_execve
3061debfc3dSmrg /* A wrapper for the execve function. Flushes the accumulated
3071debfc3dSmrg profiling data, so that they are not lost. */
3081debfc3dSmrg
3091debfc3dSmrg int
__gcov_execve(const char * path,char * const argv[],char * const envp[])3101debfc3dSmrg __gcov_execve (const char *path, char *const argv[], char *const envp[])
3111debfc3dSmrg {
3121debfc3dSmrg __gcov_flush ();
3131debfc3dSmrg return execve (path, argv, envp);
3141debfc3dSmrg }
3151debfc3dSmrg #endif
3161debfc3dSmrg #endif /* inhibit_libc */
317