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