(root)/
gcc-13.2.0/
libgcc/
libgcov-interface.c
       1  /* Routines required for instrumenting a program.  */
       2  /* Compile this one with gcc.  */
       3  /* Copyright (C) 1989-2023 Free Software Foundation, Inc.
       4  
       5  This file is part of GCC.
       6  
       7  GCC is free software; you can redistribute it and/or modify it under
       8  the terms of the GNU General Public License as published by the Free
       9  Software Foundation; either version 3, or (at your option) any later
      10  version.
      11  
      12  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15  for more details.
      16  
      17  Under Section 7 of GPL version 3, you are granted additional
      18  permissions described in the GCC Runtime Library Exception, version
      19  3.1, as published by the Free Software Foundation.
      20  
      21  You should have received a copy of the GNU General Public License and
      22  a copy of the GCC Runtime Library Exception along with this program;
      23  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      24  <http://www.gnu.org/licenses/>.  */
      25  
      26  #include "libgcov.h"
      27  #include "gthr.h"
      28  
      29  #if defined(inhibit_libc)
      30  
      31  #ifdef L_gcov_reset
      32  void __gcov_reset (void) {}
      33  #endif
      34  
      35  #ifdef L_gcov_dump
      36  void __gcov_dump (void) {}
      37  #endif
      38  
      39  #else
      40  
      41  extern __gthread_mutex_t __gcov_mx ATTRIBUTE_HIDDEN;
      42  
      43  #ifdef L_gcov_lock_unlock
      44  #ifdef __GTHREAD_MUTEX_INIT
      45  __gthread_mutex_t __gcov_mx = __GTHREAD_MUTEX_INIT;
      46  #define init_mx_once()
      47  #else
      48  __gthread_mutex_t __gcov_mx;
      49  
      50  static void
      51  init_mx (void)
      52  {
      53    __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_mx);
      54  }
      55  
      56  static void
      57  init_mx_once (void)
      58  {
      59    static __gthread_once_t once = __GTHREAD_ONCE_INIT;
      60    __gthread_once (&once, init_mx);
      61  }
      62  #endif
      63  
      64  /* Lock critical section for __gcov_dump and __gcov_reset functions.  */
      65  
      66  void
      67  __gcov_lock (void)
      68  {
      69    init_mx_once ();
      70    __gthread_mutex_lock (&__gcov_mx);
      71  }
      72  
      73  /* Unlock critical section for __gcov_dump and __gcov_reset functions.  */
      74  
      75  void
      76  __gcov_unlock (void)
      77  {
      78    __gthread_mutex_unlock (&__gcov_mx);
      79  }
      80  #endif
      81  
      82  #ifdef L_gcov_reset
      83  
      84  /* Reset all counters to zero.  */
      85  
      86  static void
      87  gcov_clear (const struct gcov_info *list)
      88  {
      89    const struct gcov_info *gi_ptr;
      90  
      91    for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
      92      {
      93        unsigned f_ix;
      94  
      95        for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
      96          {
      97            unsigned t_ix;
      98            const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
      99  
     100            if (!gfi_ptr || gfi_ptr->key != gi_ptr)
     101              continue;
     102            const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
     103            for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
     104              {
     105                if (!gi_ptr->merge[t_ix])
     106                  continue;
     107  
     108                memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
     109                ci_ptr++;
     110              }
     111          }
     112      }
     113  }
     114  
     115  /* Function that can be called from application to reset counters to zero,
     116     in order to collect profile in region of interest.  */
     117  
     118  void
     119  __gcov_reset_int (void)
     120  {
     121    struct gcov_root *root;
     122  
     123    /* If we're compatible with the master, iterate over everything,
     124       otherise just do us.  */
     125    for (root = __gcov_master.version == GCOV_VERSION
     126  	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
     127      {
     128        gcov_clear (root->list);
     129        root->dumped = 0;
     130      }
     131  }
     132  
     133  /* Exported function __gcov_reset.  */
     134  
     135  void
     136  __gcov_reset (void)
     137  {
     138    __gcov_lock ();
     139  
     140    __gcov_reset_int ();
     141  
     142    __gcov_unlock ();
     143  }
     144  
     145  #endif /* L_gcov_reset */
     146  
     147  #ifdef L_gcov_dump
     148  /* Function that can be called from application to write profile collected
     149     so far, in order to collect profile in region of interest.  */
     150  
     151  void
     152  __gcov_dump_int (void)
     153  {
     154    struct gcov_root *root;
     155  
     156    /* If we're compatible with the master, iterate over everything,
     157       otherise just do us.  */
     158    for (root = __gcov_master.version == GCOV_VERSION
     159  	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
     160      __gcov_dump_one (root);
     161  }
     162  
     163  /* Exported function __gcov_dump.  */
     164  
     165  void
     166  __gcov_dump (void)
     167  {
     168    __gcov_lock ();
     169  
     170    __gcov_dump_int ();
     171  
     172    __gcov_unlock ();
     173  }
     174  
     175  #endif /* L_gcov_dump */
     176  
     177  #ifdef L_gcov_fork
     178  /* A wrapper for the fork function.  We reset counters in the child
     179     so that they are not counted twice.  */
     180  
     181  pid_t
     182  __gcov_fork (void)
     183  {
     184    pid_t pid;
     185    pid = fork ();
     186    if (pid == 0)
     187      {
     188        __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_mx);
     189        /* We do not need locking as we are the only thread in the child.  */
     190        __gcov_reset_int ();
     191      }
     192    return pid;
     193  }
     194  #endif
     195  
     196  #ifdef L_gcov_execl
     197  /* A wrapper for the execl function.  Flushes the accumulated
     198     profiling data, so that they are not lost.  */
     199  
     200  int
     201  __gcov_execl (const char *path, char *arg, ...)
     202  {
     203    va_list ap, aq;
     204    unsigned i, length;
     205    char **args;
     206  
     207    /* Dump counters only, they will be lost after exec.  */
     208    __gcov_dump ();
     209  
     210    va_start (ap, arg);
     211    va_copy (aq, ap);
     212  
     213    length = 2;
     214    while (va_arg (ap, char *))
     215      length++;
     216    va_end (ap);
     217  
     218    args = (char **) alloca (length * sizeof (void *));
     219    args[0] = arg;
     220    for (i = 1; i < length; i++)
     221      args[i] = va_arg (aq, char *);
     222    va_end (aq);
     223  
     224    int ret = execv (path, args);
     225    /* We reach this code only when execv fails, reset counter then here.  */
     226    __gcov_reset ();
     227    return ret;
     228  }
     229  #endif
     230  
     231  #ifdef L_gcov_execlp
     232  /* A wrapper for the execlp function.  Flushes the accumulated
     233     profiling data, so that they are not lost.  */
     234  
     235  int
     236  __gcov_execlp (const char *path, char *arg, ...)
     237  {
     238    va_list ap, aq;
     239    unsigned i, length;
     240    char **args;
     241  
     242    /* Dump counters only, they will be lost after exec.  */
     243    __gcov_dump ();
     244  
     245    va_start (ap, arg);
     246    va_copy (aq, ap);
     247  
     248    length = 2;
     249    while (va_arg (ap, char *))
     250      length++;
     251    va_end (ap);
     252  
     253    args = (char **) alloca (length * sizeof (void *));
     254    args[0] = arg;
     255    for (i = 1; i < length; i++)
     256      args[i] = va_arg (aq, char *);
     257    va_end (aq);
     258  
     259    int ret = execvp (path, args);
     260    /* We reach this code only when execv fails, reset counter then here.  */
     261    __gcov_reset ();
     262    return ret;
     263  }
     264  #endif
     265  
     266  #ifdef L_gcov_execle
     267  /* A wrapper for the execle function.  Flushes the accumulated
     268     profiling data, so that they are not lost.  */
     269  
     270  int
     271  __gcov_execle (const char *path, char *arg, ...)
     272  {
     273    va_list ap, aq;
     274    unsigned i, length;
     275    char **args;
     276    char **envp;
     277  
     278    /* Dump counters only, they will be lost after exec.  */
     279    __gcov_dump ();
     280  
     281    va_start (ap, arg);
     282    va_copy (aq, ap);
     283  
     284    length = 2;
     285    while (va_arg (ap, char *))
     286      length++;
     287    va_end (ap);
     288  
     289    args = (char **) alloca (length * sizeof (void *));
     290    args[0] = arg;
     291    for (i = 1; i < length; i++)
     292      args[i] = va_arg (aq, char *);
     293    envp = va_arg (aq, char **);
     294    va_end (aq);
     295  
     296    int ret = execve (path, args, envp);
     297    /* We reach this code only when execv fails, reset counter then here.  */
     298    __gcov_reset ();
     299    return ret;
     300  }
     301  #endif
     302  
     303  #ifdef L_gcov_execv
     304  /* A wrapper for the execv function.  Flushes the accumulated
     305     profiling data, so that they are not lost.  */
     306  
     307  int
     308  __gcov_execv (const char *path, char *const argv[])
     309  {
     310    /* Dump counters only, they will be lost after exec.  */
     311    __gcov_dump ();
     312    int ret = execv (path, argv);
     313    /* We reach this code only when execv fails, reset counter then here.  */
     314    __gcov_reset ();
     315    return ret;
     316  }
     317  #endif
     318  
     319  #ifdef L_gcov_execvp
     320  /* A wrapper for the execvp function.  Flushes the accumulated
     321     profiling data, so that they are not lost.  */
     322  
     323  int
     324  __gcov_execvp (const char *path, char *const argv[])
     325  {
     326    /* Dump counters only, they will be lost after exec.  */
     327    __gcov_dump ();
     328    int ret = execvp (path, argv);
     329    /* We reach this code only when execv fails, reset counter then here.  */
     330    __gcov_reset ();
     331    return ret;
     332  }
     333  #endif
     334  
     335  #ifdef L_gcov_execve
     336  /* A wrapper for the execve function.  Flushes the accumulated
     337     profiling data, so that they are not lost.  */
     338  
     339  int
     340  __gcov_execve (const char *path, char *const argv[], char *const envp[])
     341  {
     342    /* Dump counters only, they will be lost after exec.  */
     343    __gcov_dump ();
     344    int ret = execve (path, argv, envp);
     345    /* We reach this code only when execv fails, reset counter then here.  */
     346    __gcov_reset ();
     347    return ret;
     348  }
     349  #endif
     350  #endif /* inhibit_libc */