xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/libgcov-interface.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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