Home | History | Annotate | Line # | Download | only in libgcc
      1 /* Routines required for instrumenting a program.  */
      2 /* Compile this one with gcc.  */
      3 /* Copyright (C) 1989-2024 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 = __builtin_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 */
    351