Home | History | Annotate | Line # | Download | only in libgcc
libgcov-interface.c revision 1.1.1.6
      1 /* Routines required for instrumenting a program.  */
      2 /* Compile this one with gcc.  */
      3 /* Copyright (C) 1989-2020 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_flush
     32 void __gcov_flush (void) {}
     33 #endif
     34 
     35 #ifdef L_gcov_reset
     36 void __gcov_reset (void) {}
     37 #endif
     38 
     39 #ifdef L_gcov_dump
     40 void __gcov_dump (void) {}
     41 #endif
     42 
     43 #else
     44 
     45 /* Some functions we want to bind in this dynamic object, but have an
     46    overridable global alias.  Unfortunately not all targets support
     47    aliases, so we just have a forwarding function.  That'll be tail
     48    called, so the cost is a single jump instruction.*/
     49 
     50 #define ALIAS_void_fn(src,dst) \
     51   void dst (void)	    \
     52   { src (); }
     53 
     54 extern __gthread_mutex_t __gcov_flush_mx ATTRIBUTE_HIDDEN;
     55 
     56 #ifdef L_gcov_flush
     57 #ifdef __GTHREAD_MUTEX_INIT
     58 __gthread_mutex_t __gcov_flush_mx = __GTHREAD_MUTEX_INIT;
     59 #define init_mx_once()
     60 #else
     61 __gthread_mutex_t __gcov_flush_mx;
     62 
     63 static void
     64 init_mx (void)
     65 {
     66   __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
     67 }
     68 
     69 static void
     70 init_mx_once (void)
     71 {
     72   static __gthread_once_t once = __GTHREAD_ONCE_INIT;
     73   __gthread_once (&once, init_mx);
     74 }
     75 #endif
     76 
     77 /* Called before fork or exec - write out profile information gathered so
     78    far and reset it to zero.  This avoids duplication or loss of the
     79    profile information gathered so far.  */
     80 
     81 void
     82 __gcov_flush (void)
     83 {
     84   init_mx_once ();
     85   __gthread_mutex_lock (&__gcov_flush_mx);
     86 
     87   __gcov_dump_int ();
     88   __gcov_reset_int ();
     89 
     90   __gthread_mutex_unlock (&__gcov_flush_mx);
     91 }
     92 
     93 #endif /* L_gcov_flush */
     94 
     95 #ifdef L_gcov_reset
     96 
     97 /* Reset all counters to zero.  */
     98 
     99 static void
    100 gcov_clear (const struct gcov_info *list)
    101 {
    102   const struct gcov_info *gi_ptr;
    103 
    104   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    105     {
    106       unsigned f_ix;
    107 
    108       for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
    109         {
    110           unsigned t_ix;
    111           const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
    112 
    113           if (!gfi_ptr || gfi_ptr->key != gi_ptr)
    114             continue;
    115           const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
    116           for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
    117             {
    118               if (!gi_ptr->merge[t_ix])
    119                 continue;
    120 
    121               memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
    122               ci_ptr++;
    123             }
    124         }
    125     }
    126 }
    127 
    128 /* Function that can be called from application to reset counters to zero,
    129    in order to collect profile in region of interest.  */
    130 
    131 void
    132 __gcov_reset_int (void)
    133 {
    134   struct gcov_root *root;
    135 
    136   /* If we're compatible with the master, iterate over everything,
    137      otherise just do us.  */
    138   for (root = __gcov_master.version == GCOV_VERSION
    139 	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
    140     {
    141       gcov_clear (root->list);
    142       root->dumped = 0;
    143     }
    144 }
    145 
    146 ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
    147 
    148 #endif /* L_gcov_reset */
    149 
    150 #ifdef L_gcov_dump
    151 /* Function that can be called from application to write profile collected
    152    so far, in order to collect profile in region of interest.  */
    153 
    154 void
    155 __gcov_dump_int (void)
    156 {
    157   struct gcov_root *root;
    158 
    159   /* If we're compatible with the master, iterate over everything,
    160      otherise just do us.  */
    161   for (root = __gcov_master.version == GCOV_VERSION
    162 	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
    163     __gcov_dump_one (root);
    164 }
    165 
    166 ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
    167 
    168 #endif /* L_gcov_dump */
    169 
    170 #ifdef L_gcov_fork
    171 /* A wrapper for the fork function.  Flushes the accumulated profiling data, so
    172    that they are not counted twice.  */
    173 
    174 pid_t
    175 __gcov_fork (void)
    176 {
    177   pid_t pid;
    178   __gcov_flush ();
    179   pid = fork ();
    180   if (pid == 0)
    181     __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_flush_mx);
    182   return pid;
    183 }
    184 #endif
    185 
    186 #ifdef L_gcov_execl
    187 /* A wrapper for the execl function.  Flushes the accumulated
    188    profiling data, so that they are not lost.  */
    189 
    190 int
    191 __gcov_execl (const char *path, char *arg, ...)
    192 {
    193   va_list ap, aq;
    194   unsigned i, length;
    195   char **args;
    196 
    197   __gcov_flush ();
    198 
    199   va_start (ap, arg);
    200   va_copy (aq, ap);
    201 
    202   length = 2;
    203   while (va_arg (ap, char *))
    204     length++;
    205   va_end (ap);
    206 
    207   args = (char **) alloca (length * sizeof (void *));
    208   args[0] = arg;
    209   for (i = 1; i < length; i++)
    210     args[i] = va_arg (aq, char *);
    211   va_end (aq);
    212 
    213   return execv (path, args);
    214 }
    215 #endif
    216 
    217 #ifdef L_gcov_execlp
    218 /* A wrapper for the execlp function.  Flushes the accumulated
    219    profiling data, so that they are not lost.  */
    220 
    221 int
    222 __gcov_execlp (const char *path, char *arg, ...)
    223 {
    224   va_list ap, aq;
    225   unsigned i, length;
    226   char **args;
    227 
    228   __gcov_flush ();
    229 
    230   va_start (ap, arg);
    231   va_copy (aq, ap);
    232 
    233   length = 2;
    234   while (va_arg (ap, char *))
    235     length++;
    236   va_end (ap);
    237 
    238   args = (char **) alloca (length * sizeof (void *));
    239   args[0] = arg;
    240   for (i = 1; i < length; i++)
    241     args[i] = va_arg (aq, char *);
    242   va_end (aq);
    243 
    244   return execvp (path, args);
    245 }
    246 #endif
    247 
    248 #ifdef L_gcov_execle
    249 /* A wrapper for the execle function.  Flushes the accumulated
    250    profiling data, so that they are not lost.  */
    251 
    252 int
    253 __gcov_execle (const char *path, char *arg, ...)
    254 {
    255   va_list ap, aq;
    256   unsigned i, length;
    257   char **args;
    258   char **envp;
    259 
    260   __gcov_flush ();
    261 
    262   va_start (ap, arg);
    263   va_copy (aq, ap);
    264 
    265   length = 2;
    266   while (va_arg (ap, char *))
    267     length++;
    268   va_end (ap);
    269 
    270   args = (char **) alloca (length * sizeof (void *));
    271   args[0] = arg;
    272   for (i = 1; i < length; i++)
    273     args[i] = va_arg (aq, char *);
    274   envp = va_arg (aq, char **);
    275   va_end (aq);
    276 
    277   return execve (path, args, envp);
    278 }
    279 #endif
    280 
    281 #ifdef L_gcov_execv
    282 /* A wrapper for the execv function.  Flushes the accumulated
    283    profiling data, so that they are not lost.  */
    284 
    285 int
    286 __gcov_execv (const char *path, char *const argv[])
    287 {
    288   __gcov_flush ();
    289   return execv (path, argv);
    290 }
    291 #endif
    292 
    293 #ifdef L_gcov_execvp
    294 /* A wrapper for the execvp function.  Flushes the accumulated
    295    profiling data, so that they are not lost.  */
    296 
    297 int
    298 __gcov_execvp (const char *path, char *const argv[])
    299 {
    300   __gcov_flush ();
    301   return execvp (path, argv);
    302 }
    303 #endif
    304 
    305 #ifdef L_gcov_execve
    306 /* A wrapper for the execve function.  Flushes the accumulated
    307    profiling data, so that they are not lost.  */
    308 
    309 int
    310 __gcov_execve (const char *path, char *const argv[], char *const envp[])
    311 {
    312   __gcov_flush ();
    313   return execve (path, argv, envp);
    314 }
    315 #endif
    316 #endif /* inhibit_libc */
    317