Home | History | Annotate | Line # | Download | only in libgcc
libgcov-driver.c revision 1.1.1.10
      1       1.1  mrg /* Routines required for instrumenting a program.  */
      2       1.1  mrg /* Compile this one with gcc.  */
      3  1.1.1.10  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.1.8  mrg #include "gcov-io.h"
     28       1.1  mrg 
     29  1.1.1.10  mrg /* Return 1, if all counter values are zero, otherwise 0. */
     30  1.1.1.10  mrg 
     31  1.1.1.10  mrg static inline int
     32  1.1.1.10  mrg are_all_counters_zero (const struct gcov_ctr_info *ci_ptr)
     33  1.1.1.10  mrg {
     34  1.1.1.10  mrg   for (unsigned i = 0; i < ci_ptr->num; i++)
     35  1.1.1.10  mrg     if (ci_ptr->values[i] != 0)
     36  1.1.1.10  mrg       return 0;
     37  1.1.1.10  mrg 
     38  1.1.1.10  mrg   return 1;
     39  1.1.1.10  mrg }
     40  1.1.1.10  mrg 
     41       1.1  mrg #if defined(inhibit_libc)
     42       1.1  mrg /* If libc and its header files are not available, provide dummy functions.  */
     43       1.1  mrg 
     44       1.1  mrg #if defined(L_gcov)
     45       1.1  mrg void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
     46       1.1  mrg #endif
     47       1.1  mrg 
     48       1.1  mrg #else /* inhibit_libc */
     49       1.1  mrg 
     50       1.1  mrg #if GCOV_LOCKED
     51       1.1  mrg #include <fcntl.h>
     52       1.1  mrg #include <errno.h>
     53       1.1  mrg #include <sys/stat.h>
     54  1.1.1.10  mrg #elif GCOV_LOCKED_WITH_LOCKING
     55  1.1.1.10  mrg #include <fcntl.h>
     56  1.1.1.10  mrg #include <sys/locking.h>
     57  1.1.1.10  mrg #include <sys/stat.h>
     58  1.1.1.10  mrg #endif
     59  1.1.1.10  mrg 
     60  1.1.1.10  mrg #if HAVE_SYS_MMAN_H
     61  1.1.1.10  mrg #include <sys/mman.h>
     62  1.1.1.10  mrg #endif
     63  1.1.1.10  mrg 
     64  1.1.1.10  mrg #endif /* inhibit_libc */
     65  1.1.1.10  mrg 
     66  1.1.1.10  mrg #if defined(L_gcov) && !defined(inhibit_libc)
     67  1.1.1.10  mrg #define NEED_L_GCOV
     68       1.1  mrg #endif
     69       1.1  mrg 
     70  1.1.1.10  mrg #if defined(L_gcov_info_to_gcda) && !IN_GCOV_TOOL
     71  1.1.1.10  mrg #define NEED_L_GCOV_INFO_TO_GCDA
     72  1.1.1.10  mrg #endif
     73       1.1  mrg 
     74  1.1.1.10  mrg #ifdef NEED_L_GCOV
     75   1.1.1.4  mrg /* A utility function for outputting errors.  */
     76       1.1  mrg static int gcov_error (const char *, ...);
     77       1.1  mrg 
     78   1.1.1.4  mrg #if !IN_GCOV_TOOL
     79   1.1.1.4  mrg static void gcov_error_exit (void);
     80   1.1.1.4  mrg #endif
     81   1.1.1.4  mrg 
     82  1.1.1.10  mrg #include "gcov-io.cc"
     83       1.1  mrg 
     84   1.1.1.8  mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
     85   1.1.1.8  mrg 
     86       1.1  mrg struct gcov_fn_buffer
     87       1.1  mrg {
     88       1.1  mrg   struct gcov_fn_buffer *next;
     89       1.1  mrg   unsigned fn_ix;
     90       1.1  mrg   struct gcov_fn_info info;
     91       1.1  mrg   /* note gcov_fn_info ends in a trailing array.  */
     92       1.1  mrg };
     93       1.1  mrg 
     94       1.1  mrg struct gcov_summary_buffer
     95       1.1  mrg {
     96       1.1  mrg   struct gcov_summary_buffer *next;
     97       1.1  mrg   struct gcov_summary summary;
     98       1.1  mrg };
     99       1.1  mrg 
    100       1.1  mrg /* A struct that bundles all the related information about the
    101       1.1  mrg    gcda filename.  */
    102       1.1  mrg 
    103       1.1  mrg struct gcov_filename
    104       1.1  mrg {
    105       1.1  mrg   char *filename;  /* filename buffer */
    106       1.1  mrg   int strip; /* leading chars to strip from filename */
    107   1.1.1.8  mrg   char *prefix; /* prefix string */
    108       1.1  mrg };
    109       1.1  mrg 
    110       1.1  mrg static struct gcov_fn_buffer *
    111       1.1  mrg free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
    112       1.1  mrg               unsigned limit)
    113       1.1  mrg {
    114       1.1  mrg   struct gcov_fn_buffer *next;
    115       1.1  mrg   unsigned ix, n_ctr = 0;
    116       1.1  mrg 
    117       1.1  mrg   if (!buffer)
    118       1.1  mrg     return 0;
    119       1.1  mrg   next = buffer->next;
    120       1.1  mrg 
    121       1.1  mrg   for (ix = 0; ix != limit; ix++)
    122       1.1  mrg     if (gi_ptr->merge[ix])
    123       1.1  mrg       free (buffer->info.ctrs[n_ctr++].values);
    124       1.1  mrg   free (buffer);
    125       1.1  mrg   return next;
    126       1.1  mrg }
    127       1.1  mrg 
    128       1.1  mrg static struct gcov_fn_buffer **
    129       1.1  mrg buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
    130       1.1  mrg                 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
    131       1.1  mrg {
    132       1.1  mrg   unsigned n_ctrs = 0, ix = 0;
    133       1.1  mrg   struct gcov_fn_buffer *fn_buffer;
    134       1.1  mrg   unsigned len;
    135       1.1  mrg 
    136       1.1  mrg   for (ix = GCOV_COUNTERS; ix--;)
    137       1.1  mrg     if (gi_ptr->merge[ix])
    138       1.1  mrg       n_ctrs++;
    139       1.1  mrg 
    140       1.1  mrg   len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
    141       1.1  mrg   fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
    142       1.1  mrg 
    143       1.1  mrg   if (!fn_buffer)
    144       1.1  mrg     goto fail;
    145       1.1  mrg 
    146       1.1  mrg   fn_buffer->next = 0;
    147       1.1  mrg   fn_buffer->fn_ix = fn_ix;
    148       1.1  mrg   fn_buffer->info.ident = gcov_read_unsigned ();
    149       1.1  mrg   fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
    150       1.1  mrg   fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
    151       1.1  mrg 
    152       1.1  mrg   for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
    153       1.1  mrg     {
    154       1.1  mrg       gcov_unsigned_t length;
    155       1.1  mrg       gcov_type *values;
    156       1.1  mrg 
    157       1.1  mrg       if (!gi_ptr->merge[ix])
    158       1.1  mrg         continue;
    159       1.1  mrg 
    160       1.1  mrg       if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
    161       1.1  mrg         {
    162       1.1  mrg           len = 0;
    163       1.1  mrg           goto fail;
    164       1.1  mrg         }
    165       1.1  mrg 
    166       1.1  mrg       length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
    167       1.1  mrg       len = length * sizeof (gcov_type);
    168       1.1  mrg       values = (gcov_type *) xmalloc (len);
    169       1.1  mrg       if (!values)
    170       1.1  mrg         goto fail;
    171       1.1  mrg 
    172       1.1  mrg       fn_buffer->info.ctrs[n_ctrs].num = length;
    173       1.1  mrg       fn_buffer->info.ctrs[n_ctrs].values = values;
    174       1.1  mrg 
    175       1.1  mrg       while (length--)
    176       1.1  mrg         *values++ = gcov_read_counter ();
    177       1.1  mrg       n_ctrs++;
    178       1.1  mrg     }
    179       1.1  mrg 
    180       1.1  mrg   *end_ptr = fn_buffer;
    181       1.1  mrg   return &fn_buffer->next;
    182       1.1  mrg 
    183       1.1  mrg fail:
    184   1.1.1.8  mrg   gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
    185       1.1  mrg               len ? "cannot allocate" : "counter mismatch", len ? len : ix);
    186       1.1  mrg 
    187       1.1  mrg   return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
    188       1.1  mrg }
    189       1.1  mrg 
    190   1.1.1.8  mrg /* Convert VERSION into a string description and return the it.
    191   1.1.1.8  mrg    BUFFER is used for storage of the string.  The code should be
    192   1.1.1.8  mrg    aligned wit gcov-iov.c.  */
    193   1.1.1.8  mrg 
    194   1.1.1.8  mrg static char *
    195   1.1.1.8  mrg gcov_version_string (char *buffer, char version[4])
    196   1.1.1.8  mrg {
    197   1.1.1.8  mrg   if (version[0] < 'A' || version[0] > 'Z'
    198   1.1.1.8  mrg       || version[1] < '0' || version[1] > '9'
    199   1.1.1.8  mrg       || version[2] < '0' || version[2] > '9')
    200   1.1.1.8  mrg     sprintf (buffer, "(unknown)");
    201   1.1.1.8  mrg   else
    202       1.1  mrg     {
    203   1.1.1.8  mrg       unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
    204   1.1.1.8  mrg       unsigned minor = version[2] - '0';
    205   1.1.1.8  mrg       sprintf (buffer, "%u.%u (%s)", major, minor,
    206   1.1.1.8  mrg 	       version[3] == '*' ? "release" : "experimental");
    207       1.1  mrg     }
    208   1.1.1.8  mrg   return buffer;
    209       1.1  mrg }
    210       1.1  mrg 
    211       1.1  mrg /* Check if VERSION of the info block PTR matches libgcov one.
    212       1.1  mrg    Return 1 on success, or zero in case of versions mismatch.
    213       1.1  mrg    If FILENAME is not NULL, its value used for reporting purposes
    214       1.1  mrg    instead of value from the info block.  */
    215       1.1  mrg 
    216       1.1  mrg static int
    217       1.1  mrg gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
    218       1.1  mrg               const char *filename)
    219       1.1  mrg {
    220       1.1  mrg   if (version != GCOV_VERSION)
    221       1.1  mrg     {
    222       1.1  mrg       char v[4], e[4];
    223  1.1.1.10  mrg       char ver_string[128], expected_string[128];
    224       1.1  mrg 
    225       1.1  mrg       GCOV_UNSIGNED2STRING (v, version);
    226       1.1  mrg       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
    227       1.1  mrg 
    228   1.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
    229   1.1.1.8  mrg 		  "got %s (%.4s)\n",
    230   1.1.1.8  mrg 		  filename? filename : ptr->filename,
    231   1.1.1.8  mrg 		  gcov_version_string (expected_string, e), e,
    232  1.1.1.10  mrg 		  gcov_version_string (ver_string, v), v);
    233       1.1  mrg       return 0;
    234       1.1  mrg     }
    235       1.1  mrg   return 1;
    236       1.1  mrg }
    237       1.1  mrg 
    238       1.1  mrg /* buffer for the fn_data from another program.  */
    239       1.1  mrg static struct gcov_fn_buffer *fn_buffer;
    240       1.1  mrg 
    241       1.1  mrg /* Including system dependent components. */
    242       1.1  mrg #include "libgcov-driver-system.c"
    243       1.1  mrg 
    244       1.1  mrg /* This function merges counters in GI_PTR to an existing gcda file.
    245       1.1  mrg    Return 0 on success.
    246       1.1  mrg    Return -1 on error. In this case, caller will goto read_fatal.  */
    247       1.1  mrg 
    248       1.1  mrg static int
    249       1.1  mrg merge_one_data (const char *filename,
    250       1.1  mrg 		struct gcov_info *gi_ptr,
    251   1.1.1.8  mrg 		struct gcov_summary *summary)
    252       1.1  mrg {
    253       1.1  mrg   gcov_unsigned_t tag, length;
    254       1.1  mrg   unsigned t_ix;
    255   1.1.1.8  mrg   int f_ix = -1;
    256       1.1  mrg   int error = 0;
    257       1.1  mrg   struct gcov_fn_buffer **fn_tail = &fn_buffer;
    258       1.1  mrg 
    259       1.1  mrg   length = gcov_read_unsigned ();
    260       1.1  mrg   if (!gcov_version (gi_ptr, length, filename))
    261       1.1  mrg     return -1;
    262       1.1  mrg 
    263  1.1.1.10  mrg   /* Skip timestamp.  */
    264  1.1.1.10  mrg   gcov_read_unsigned ();
    265  1.1.1.10  mrg 
    266       1.1  mrg   length = gcov_read_unsigned ();
    267  1.1.1.10  mrg   if (length != gi_ptr->checksum)
    268       1.1  mrg     {
    269   1.1.1.8  mrg       /* Read from a different compilation.  Overwrite the file.  */
    270   1.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
    271  1.1.1.10  mrg 		  "with a different checksum\n", filename);
    272   1.1.1.8  mrg       return 0;
    273       1.1  mrg     }
    274       1.1  mrg 
    275   1.1.1.8  mrg   tag = gcov_read_unsigned ();
    276   1.1.1.8  mrg   if (tag != GCOV_TAG_OBJECT_SUMMARY)
    277   1.1.1.8  mrg     goto read_mismatch;
    278   1.1.1.8  mrg   length = gcov_read_unsigned ();
    279   1.1.1.8  mrg   gcc_assert (length > 0);
    280   1.1.1.8  mrg   gcov_read_summary (summary);
    281   1.1.1.8  mrg 
    282   1.1.1.8  mrg   tag = gcov_read_unsigned ();
    283       1.1  mrg   /* Merge execution counts for each function.  */
    284       1.1  mrg   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
    285       1.1  mrg        f_ix++, tag = gcov_read_unsigned ())
    286       1.1  mrg     {
    287       1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    288       1.1  mrg       const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
    289       1.1  mrg 
    290       1.1  mrg       if (tag != GCOV_TAG_FUNCTION)
    291       1.1  mrg         goto read_mismatch;
    292       1.1  mrg 
    293       1.1  mrg       length = gcov_read_unsigned ();
    294       1.1  mrg       if (!length)
    295       1.1  mrg         /* This function did not appear in the other program.
    296       1.1  mrg            We have nothing to merge.  */
    297       1.1  mrg         continue;
    298       1.1  mrg 
    299       1.1  mrg       if (length != GCOV_TAG_FUNCTION_LENGTH)
    300       1.1  mrg         goto read_mismatch;
    301       1.1  mrg 
    302       1.1  mrg       if (!gfi_ptr || gfi_ptr->key != gi_ptr)
    303       1.1  mrg         {
    304       1.1  mrg           /* This function appears in the other program.  We
    305       1.1  mrg              need to buffer the information in order to write
    306       1.1  mrg              it back out -- we'll be inserting data before
    307       1.1  mrg              this point, so cannot simply keep the data in the
    308       1.1  mrg              file.  */
    309       1.1  mrg           fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
    310       1.1  mrg           if (!fn_tail)
    311       1.1  mrg             goto read_mismatch;
    312       1.1  mrg           continue;
    313       1.1  mrg         }
    314       1.1  mrg 
    315       1.1  mrg       length = gcov_read_unsigned ();
    316       1.1  mrg       if (length != gfi_ptr->ident)
    317       1.1  mrg         goto read_mismatch;
    318       1.1  mrg 
    319       1.1  mrg       length = gcov_read_unsigned ();
    320       1.1  mrg       if (length != gfi_ptr->lineno_checksum)
    321       1.1  mrg         goto read_mismatch;
    322       1.1  mrg 
    323       1.1  mrg       length = gcov_read_unsigned ();
    324       1.1  mrg       if (length != gfi_ptr->cfg_checksum)
    325       1.1  mrg         goto read_mismatch;
    326       1.1  mrg 
    327       1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    328       1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    329       1.1  mrg         {
    330       1.1  mrg           gcov_merge_fn merge = gi_ptr->merge[t_ix];
    331       1.1  mrg 
    332       1.1  mrg           if (!merge)
    333       1.1  mrg             continue;
    334       1.1  mrg 
    335  1.1.1.10  mrg 	  tag = gcov_read_unsigned ();
    336  1.1.1.10  mrg 	  int read_length = (int)gcov_read_unsigned ();
    337  1.1.1.10  mrg 	  length = abs (read_length);
    338  1.1.1.10  mrg 	  if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
    339  1.1.1.10  mrg 	      || (length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num)
    340  1.1.1.10  mrg 		  && t_ix != GCOV_COUNTER_V_TOPN
    341  1.1.1.10  mrg 		  && t_ix != GCOV_COUNTER_V_INDIR))
    342  1.1.1.10  mrg 	    goto read_mismatch;
    343  1.1.1.10  mrg 	  /* Merging with all zero counters does not make sense.  */
    344  1.1.1.10  mrg 	  if (read_length > 0)
    345  1.1.1.10  mrg 	    (*merge) (ci_ptr->values, ci_ptr->num);
    346  1.1.1.10  mrg 	  ci_ptr++;
    347  1.1.1.10  mrg 	}
    348       1.1  mrg       if ((error = gcov_is_error ()))
    349  1.1.1.10  mrg 	goto read_error;
    350       1.1  mrg     }
    351       1.1  mrg 
    352       1.1  mrg   if (tag)
    353       1.1  mrg     {
    354       1.1  mrg     read_mismatch:;
    355   1.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
    356       1.1  mrg                   filename, f_ix >= 0 ? "function" : "summary",
    357       1.1  mrg                   f_ix < 0 ? -1 - f_ix : f_ix);
    358       1.1  mrg       return -1;
    359       1.1  mrg     }
    360       1.1  mrg   return 0;
    361       1.1  mrg 
    362       1.1  mrg read_error:
    363   1.1.1.8  mrg   gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
    364       1.1  mrg               error < 0 ? "Overflow": "Error");
    365       1.1  mrg   return -1;
    366       1.1  mrg }
    367       1.1  mrg 
    368  1.1.1.10  mrg /* Write the DATA of LENGTH characters to the gcov file.  */
    369  1.1.1.10  mrg 
    370  1.1.1.10  mrg static void
    371  1.1.1.10  mrg gcov_dump_handler (const void *data,
    372  1.1.1.10  mrg 		   unsigned length,
    373  1.1.1.10  mrg 		   void *arg ATTRIBUTE_UNUSED)
    374  1.1.1.10  mrg {
    375  1.1.1.10  mrg   gcov_write (data, length);
    376  1.1.1.10  mrg }
    377  1.1.1.10  mrg 
    378  1.1.1.10  mrg /* Allocate SIZE characters and return the address of the allocated memory.  */
    379  1.1.1.10  mrg 
    380  1.1.1.10  mrg static void *
    381  1.1.1.10  mrg gcov_allocate_handler (unsigned size, void *arg ATTRIBUTE_UNUSED)
    382  1.1.1.10  mrg {
    383  1.1.1.10  mrg   return xmalloc (size);
    384  1.1.1.10  mrg }
    385  1.1.1.10  mrg #endif /* NEED_L_GCOV */
    386  1.1.1.10  mrg 
    387  1.1.1.10  mrg #if defined(NEED_L_GCOV) || defined(NEED_L_GCOV_INFO_TO_GCDA)
    388  1.1.1.10  mrg /* Dump the WORD using the DUMP handler called with ARG.  */
    389  1.1.1.10  mrg 
    390  1.1.1.10  mrg static inline void
    391  1.1.1.10  mrg dump_unsigned (gcov_unsigned_t word,
    392  1.1.1.10  mrg 	       void (*dump_fn) (const void *, unsigned, void *),
    393  1.1.1.10  mrg 	       void *arg)
    394  1.1.1.10  mrg {
    395  1.1.1.10  mrg   (*dump_fn) (&word, sizeof (word), arg);
    396  1.1.1.10  mrg }
    397  1.1.1.10  mrg 
    398  1.1.1.10  mrg /* Dump the COUNTER using the DUMP handler called with ARG.  */
    399  1.1.1.10  mrg 
    400  1.1.1.10  mrg static inline void
    401  1.1.1.10  mrg dump_counter (gcov_type counter,
    402  1.1.1.10  mrg 	      void (*dump_fn) (const void *, unsigned, void *),
    403  1.1.1.10  mrg 	      void *arg)
    404  1.1.1.10  mrg {
    405  1.1.1.10  mrg   dump_unsigned ((gcov_unsigned_t)counter, dump_fn, arg);
    406  1.1.1.10  mrg 
    407  1.1.1.10  mrg   if (sizeof (counter) > sizeof (gcov_unsigned_t))
    408  1.1.1.10  mrg     dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg);
    409  1.1.1.10  mrg   else
    410  1.1.1.10  mrg     dump_unsigned (0, dump_fn, arg);
    411  1.1.1.10  mrg }
    412  1.1.1.10  mrg 
    413  1.1.1.10  mrg #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
    414  1.1.1.10  mrg 
    415  1.1.1.10  mrg /* Store all TOP N counters where each has a dynamic length.  */
    416  1.1.1.10  mrg 
    417  1.1.1.10  mrg static void
    418  1.1.1.10  mrg write_topn_counters (const struct gcov_ctr_info *ci_ptr,
    419  1.1.1.10  mrg 		     unsigned t_ix,
    420  1.1.1.10  mrg 		     gcov_unsigned_t n_counts,
    421  1.1.1.10  mrg 		     void (*dump_fn) (const void *, unsigned, void *),
    422  1.1.1.10  mrg 		     void *(*allocate_fn)(unsigned, void *),
    423  1.1.1.10  mrg 		     void *arg)
    424  1.1.1.10  mrg {
    425  1.1.1.10  mrg   unsigned counters = n_counts / GCOV_TOPN_MEM_COUNTERS;
    426  1.1.1.10  mrg   gcc_assert (n_counts % GCOV_TOPN_MEM_COUNTERS == 0);
    427  1.1.1.10  mrg 
    428  1.1.1.10  mrg   /* It can happen in a multi-threaded environment that number of counters is
    429  1.1.1.10  mrg      different from the size of the corresponding linked lists.  */
    430  1.1.1.10  mrg #define LIST_SIZE_MIN_LENGTH 4 * 1024
    431  1.1.1.10  mrg 
    432  1.1.1.10  mrg   static unsigned *list_sizes = NULL;
    433  1.1.1.10  mrg   static unsigned list_size_length = 0;
    434  1.1.1.10  mrg 
    435  1.1.1.10  mrg   if (list_sizes == NULL || counters > list_size_length)
    436  1.1.1.10  mrg     {
    437  1.1.1.10  mrg       list_size_length = MAX (LIST_SIZE_MIN_LENGTH, 2 * counters);
    438  1.1.1.10  mrg #if !defined(inhibit_libc) && HAVE_SYS_MMAN_H
    439  1.1.1.10  mrg       list_sizes
    440  1.1.1.10  mrg 	= (unsigned *)malloc_mmap (list_size_length * sizeof (unsigned));
    441  1.1.1.10  mrg #endif
    442  1.1.1.10  mrg 
    443  1.1.1.10  mrg       /* Malloc fallback.  */
    444  1.1.1.10  mrg       if (list_sizes == NULL)
    445  1.1.1.10  mrg 	list_sizes =
    446  1.1.1.10  mrg 	  (unsigned *)(*allocate_fn) (list_size_length * sizeof (unsigned),
    447  1.1.1.10  mrg 				      arg);
    448  1.1.1.10  mrg     }
    449  1.1.1.10  mrg 
    450  1.1.1.10  mrg   unsigned pair_total = 0;
    451  1.1.1.10  mrg 
    452  1.1.1.10  mrg   for (unsigned i = 0; i < counters; i++)
    453  1.1.1.10  mrg     {
    454  1.1.1.10  mrg       gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
    455  1.1.1.10  mrg       unsigned sizes = 0;
    456  1.1.1.10  mrg 
    457  1.1.1.10  mrg       for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
    458  1.1.1.10  mrg 	   node != NULL; node = node->next)
    459  1.1.1.10  mrg 	++sizes;
    460  1.1.1.10  mrg 
    461  1.1.1.10  mrg       pair_total += sizes;
    462  1.1.1.10  mrg       list_sizes[i] = sizes;
    463  1.1.1.10  mrg     }
    464  1.1.1.10  mrg 
    465  1.1.1.10  mrg   unsigned disk_size = GCOV_TOPN_DISK_COUNTERS * counters + 2 * pair_total;
    466  1.1.1.10  mrg   dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg),
    467  1.1.1.10  mrg   dump_unsigned (GCOV_TAG_COUNTER_LENGTH (disk_size), dump_fn, arg);
    468  1.1.1.10  mrg 
    469  1.1.1.10  mrg   for (unsigned i = 0; i < counters; i++)
    470  1.1.1.10  mrg     {
    471  1.1.1.10  mrg       dump_counter (ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i], dump_fn, arg);
    472  1.1.1.10  mrg       dump_counter (list_sizes[i], dump_fn, arg);
    473  1.1.1.10  mrg       gcov_type start = ci_ptr->values[GCOV_TOPN_MEM_COUNTERS * i + 2];
    474  1.1.1.10  mrg 
    475  1.1.1.10  mrg       unsigned j = 0;
    476  1.1.1.10  mrg       for (struct gcov_kvp *node = (struct gcov_kvp *)(__INTPTR_TYPE__)start;
    477  1.1.1.10  mrg 	   j < list_sizes[i]; node = node->next, j++)
    478  1.1.1.10  mrg 	{
    479  1.1.1.10  mrg 	  dump_counter (node->value, dump_fn, arg);
    480  1.1.1.10  mrg 	  dump_counter (node->count, dump_fn, arg);
    481  1.1.1.10  mrg 	}
    482  1.1.1.10  mrg     }
    483  1.1.1.10  mrg }
    484  1.1.1.10  mrg 
    485       1.1  mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
    486       1.1  mrg    the case of appending to an existing file, SUMMARY_POS will be non-zero.
    487       1.1  mrg    We will write the file starting from SUMMAY_POS.  */
    488       1.1  mrg 
    489       1.1  mrg static void
    490       1.1  mrg write_one_data (const struct gcov_info *gi_ptr,
    491  1.1.1.10  mrg 		const struct gcov_summary *prg_p ATTRIBUTE_UNUSED,
    492  1.1.1.10  mrg 		void (*dump_fn) (const void *, unsigned, void *),
    493  1.1.1.10  mrg 		void *(*allocate_fn) (unsigned, void *),
    494  1.1.1.10  mrg 		void *arg)
    495       1.1  mrg {
    496       1.1  mrg   unsigned f_ix;
    497       1.1  mrg 
    498  1.1.1.10  mrg   dump_unsigned (GCOV_DATA_MAGIC, dump_fn, arg);
    499  1.1.1.10  mrg   dump_unsigned (GCOV_VERSION, dump_fn, arg);
    500  1.1.1.10  mrg   dump_unsigned (gi_ptr->stamp, dump_fn, arg);
    501  1.1.1.10  mrg   dump_unsigned (gi_ptr->checksum, dump_fn, arg);
    502       1.1  mrg 
    503  1.1.1.10  mrg #ifdef NEED_L_GCOV
    504       1.1  mrg   /* Generate whole program statistics.  */
    505   1.1.1.8  mrg   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
    506  1.1.1.10  mrg #endif
    507       1.1  mrg 
    508       1.1  mrg   /* Write execution counts for each function.  */
    509       1.1  mrg   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
    510       1.1  mrg     {
    511  1.1.1.10  mrg #ifdef NEED_L_GCOV
    512       1.1  mrg       unsigned buffered = 0;
    513  1.1.1.10  mrg #endif
    514       1.1  mrg       const struct gcov_fn_info *gfi_ptr;
    515       1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    516       1.1  mrg       gcov_unsigned_t length;
    517       1.1  mrg       unsigned t_ix;
    518       1.1  mrg 
    519  1.1.1.10  mrg #ifdef NEED_L_GCOV
    520       1.1  mrg       if (fn_buffer && fn_buffer->fn_ix == f_ix)
    521       1.1  mrg         {
    522       1.1  mrg           /* Buffered data from another program.  */
    523       1.1  mrg           buffered = 1;
    524       1.1  mrg           gfi_ptr = &fn_buffer->info;
    525       1.1  mrg           length = GCOV_TAG_FUNCTION_LENGTH;
    526       1.1  mrg         }
    527       1.1  mrg       else
    528  1.1.1.10  mrg #endif
    529       1.1  mrg         {
    530       1.1  mrg           gfi_ptr = gi_ptr->functions[f_ix];
    531       1.1  mrg           if (gfi_ptr && gfi_ptr->key == gi_ptr)
    532       1.1  mrg             length = GCOV_TAG_FUNCTION_LENGTH;
    533       1.1  mrg           else
    534       1.1  mrg                 length = 0;
    535       1.1  mrg         }
    536       1.1  mrg 
    537  1.1.1.10  mrg       dump_unsigned (GCOV_TAG_FUNCTION, dump_fn, arg);
    538  1.1.1.10  mrg       dump_unsigned (length, dump_fn, arg);
    539       1.1  mrg       if (!length)
    540       1.1  mrg         continue;
    541       1.1  mrg 
    542  1.1.1.10  mrg       dump_unsigned (gfi_ptr->ident, dump_fn, arg);
    543  1.1.1.10  mrg       dump_unsigned (gfi_ptr->lineno_checksum, dump_fn, arg);
    544  1.1.1.10  mrg       dump_unsigned (gfi_ptr->cfg_checksum, dump_fn, arg);
    545       1.1  mrg 
    546       1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    547       1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    548       1.1  mrg         {
    549  1.1.1.10  mrg 	  gcov_position_t n_counts;
    550       1.1  mrg 
    551  1.1.1.10  mrg 	  if (!gi_ptr->merge[t_ix])
    552  1.1.1.10  mrg 	    continue;
    553       1.1  mrg 
    554  1.1.1.10  mrg 	  n_counts = ci_ptr->num;
    555  1.1.1.10  mrg 
    556  1.1.1.10  mrg 	  if (t_ix == GCOV_COUNTER_V_TOPN || t_ix == GCOV_COUNTER_V_INDIR)
    557  1.1.1.10  mrg 	    write_topn_counters (ci_ptr, t_ix, n_counts, dump_fn, allocate_fn,
    558  1.1.1.10  mrg 				 arg);
    559  1.1.1.10  mrg 	  else
    560  1.1.1.10  mrg 	    {
    561  1.1.1.10  mrg 	      dump_unsigned (GCOV_TAG_FOR_COUNTER (t_ix), dump_fn, arg);
    562  1.1.1.10  mrg 	      if (are_all_counters_zero (ci_ptr))
    563  1.1.1.10  mrg 		/* Do not stream when all counters are zero.  */
    564  1.1.1.10  mrg 		dump_unsigned (GCOV_TAG_COUNTER_LENGTH (-n_counts),
    565  1.1.1.10  mrg 			       dump_fn, arg);
    566  1.1.1.10  mrg 	      else
    567  1.1.1.10  mrg 		{
    568  1.1.1.10  mrg 		  dump_unsigned (GCOV_TAG_COUNTER_LENGTH (n_counts),
    569  1.1.1.10  mrg 				 dump_fn, arg);
    570  1.1.1.10  mrg 		  for (unsigned i = 0; i < n_counts; i++)
    571  1.1.1.10  mrg 		    dump_counter (ci_ptr->values[i], dump_fn, arg);
    572  1.1.1.10  mrg 		}
    573  1.1.1.10  mrg 	    }
    574  1.1.1.10  mrg 
    575  1.1.1.10  mrg 	  ci_ptr++;
    576  1.1.1.10  mrg 	}
    577  1.1.1.10  mrg #ifdef NEED_L_GCOV
    578       1.1  mrg       if (buffered)
    579       1.1  mrg         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    580  1.1.1.10  mrg #endif
    581       1.1  mrg     }
    582       1.1  mrg 
    583  1.1.1.10  mrg   dump_unsigned (0, dump_fn, arg);
    584       1.1  mrg }
    585  1.1.1.10  mrg #endif /* NEED_L_GCOV || NEED_L_GCOV_INFO_TO_GCDA */
    586       1.1  mrg 
    587  1.1.1.10  mrg #ifdef NEED_L_GCOV
    588       1.1  mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
    589       1.1  mrg    counts when possible, to avoid growing the .da files ad infinitum. We use
    590       1.1  mrg    this program's checksum to make sure we only accumulate whole program
    591       1.1  mrg    statistics to the correct summary. An object file might be embedded
    592       1.1  mrg    in two separate programs, and we must keep the two program
    593       1.1  mrg    summaries separate.  */
    594       1.1  mrg 
    595       1.1  mrg static void
    596       1.1  mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
    597  1.1.1.10  mrg 	       unsigned run_counted ATTRIBUTE_UNUSED,
    598  1.1.1.10  mrg 	       gcov_type run_max ATTRIBUTE_UNUSED)
    599       1.1  mrg {
    600   1.1.1.8  mrg   struct gcov_summary summary = {};
    601       1.1  mrg   int error;
    602       1.1  mrg   gcov_unsigned_t tag;
    603       1.1  mrg   fn_buffer = 0;
    604       1.1  mrg 
    605       1.1  mrg   error = gcov_exit_open_gcda_file (gi_ptr, gf);
    606       1.1  mrg   if (error == -1)
    607       1.1  mrg     return;
    608       1.1  mrg 
    609       1.1  mrg   tag = gcov_read_unsigned ();
    610       1.1  mrg   if (tag)
    611       1.1  mrg     {
    612       1.1  mrg       /* Merge data from file.  */
    613       1.1  mrg       if (tag != GCOV_DATA_MAGIC)
    614       1.1  mrg         {
    615   1.1.1.8  mrg 	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
    616   1.1.1.8  mrg 		      gf->filename);
    617       1.1  mrg           goto read_fatal;
    618       1.1  mrg         }
    619   1.1.1.8  mrg       error = merge_one_data (gf->filename, gi_ptr, &summary);
    620       1.1  mrg       if (error == -1)
    621       1.1  mrg         goto read_fatal;
    622       1.1  mrg     }
    623       1.1  mrg 
    624       1.1  mrg   gcov_rewrite ();
    625       1.1  mrg 
    626  1.1.1.10  mrg #if !IN_GCOV_TOOL
    627  1.1.1.10  mrg   if (!run_counted)
    628  1.1.1.10  mrg     {
    629  1.1.1.10  mrg       summary.runs++;
    630  1.1.1.10  mrg       summary.sum_max += run_max;
    631  1.1.1.10  mrg     }
    632  1.1.1.10  mrg #else
    633  1.1.1.10  mrg   summary = gi_ptr->summary;
    634  1.1.1.10  mrg #endif
    635       1.1  mrg 
    636  1.1.1.10  mrg   write_one_data (gi_ptr, &summary, gcov_dump_handler, gcov_allocate_handler,
    637  1.1.1.10  mrg 		  NULL);
    638       1.1  mrg   /* fall through */
    639       1.1  mrg 
    640       1.1  mrg read_fatal:;
    641       1.1  mrg   while (fn_buffer)
    642       1.1  mrg     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    643       1.1  mrg 
    644       1.1  mrg   if ((error = gcov_close ()))
    645  1.1.1.10  mrg     gcov_error ((error < 0 ? GCOV_PROF_PREFIX "Overflow writing\n"
    646  1.1.1.10  mrg 		 : GCOV_PROF_PREFIX "Error writing\n"), gf->filename);
    647       1.1  mrg }
    648       1.1  mrg 
    649       1.1  mrg 
    650       1.1  mrg /* Dump all the coverage counts for the program. It first computes program
    651       1.1  mrg    summary and then traverses gcov_list list and dumps the gcov_info
    652       1.1  mrg    objects one by one.  */
    653       1.1  mrg 
    654       1.1  mrg #if !IN_GCOV_TOOL
    655       1.1  mrg static
    656       1.1  mrg #endif
    657       1.1  mrg void
    658       1.1  mrg gcov_do_dump (struct gcov_info *list, int run_counted)
    659       1.1  mrg {
    660       1.1  mrg   struct gcov_info *gi_ptr;
    661       1.1  mrg   struct gcov_filename gf;
    662       1.1  mrg 
    663   1.1.1.8  mrg   /* Compute run_max of this program run.  */
    664   1.1.1.8  mrg   gcov_type run_max = 0;
    665   1.1.1.8  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    666   1.1.1.8  mrg     for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
    667   1.1.1.8  mrg       {
    668   1.1.1.8  mrg 	const struct gcov_ctr_info *cinfo
    669   1.1.1.8  mrg 	  = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
    670   1.1.1.8  mrg 
    671   1.1.1.8  mrg 	for (unsigned i = 0; i < cinfo->num; i++)
    672   1.1.1.8  mrg 	  if (run_max < cinfo->values[i])
    673   1.1.1.8  mrg 	    run_max = cinfo->values[i];
    674   1.1.1.8  mrg       }
    675       1.1  mrg 
    676       1.1  mrg   allocate_filename_struct (&gf);
    677       1.1  mrg 
    678       1.1  mrg   /* Now merge each file.  */
    679       1.1  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    680   1.1.1.8  mrg     {
    681   1.1.1.8  mrg       dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
    682   1.1.1.8  mrg       free (gf.filename);
    683   1.1.1.8  mrg     }
    684       1.1  mrg 
    685   1.1.1.8  mrg   free (gf.prefix);
    686       1.1  mrg }
    687       1.1  mrg 
    688   1.1.1.2  mrg #if IN_GCOV_TOOL
    689   1.1.1.2  mrg const char *
    690   1.1.1.2  mrg __attribute__ ((unused))
    691   1.1.1.2  mrg gcov_get_filename (struct gcov_info *list)
    692   1.1.1.2  mrg {
    693   1.1.1.2  mrg   return list->filename;
    694   1.1.1.2  mrg }
    695   1.1.1.2  mrg #endif
    696   1.1.1.2  mrg 
    697       1.1  mrg #if !IN_GCOV_TOOL
    698       1.1  mrg void
    699       1.1  mrg __gcov_dump_one (struct gcov_root *root)
    700       1.1  mrg {
    701       1.1  mrg   if (root->dumped)
    702       1.1  mrg     return;
    703       1.1  mrg 
    704       1.1  mrg   gcov_do_dump (root->list, root->run_counted);
    705       1.1  mrg 
    706       1.1  mrg   root->dumped = 1;
    707       1.1  mrg   root->run_counted = 1;
    708       1.1  mrg }
    709       1.1  mrg 
    710       1.1  mrg /* Per-dynamic-object gcov state.  */
    711       1.1  mrg struct gcov_root __gcov_root;
    712       1.1  mrg 
    713       1.1  mrg /* Exactly one of these will be live in the process image.  */
    714       1.1  mrg struct gcov_master __gcov_master =
    715       1.1  mrg   {GCOV_VERSION, 0};
    716       1.1  mrg 
    717  1.1.1.10  mrg /* Dynamic pool for gcov_kvp structures.  */
    718  1.1.1.10  mrg struct gcov_kvp *__gcov_kvp_dynamic_pool;
    719  1.1.1.10  mrg 
    720  1.1.1.10  mrg /* Index into __gcov_kvp_dynamic_pool array.  */
    721  1.1.1.10  mrg unsigned __gcov_kvp_dynamic_pool_index;
    722  1.1.1.10  mrg 
    723  1.1.1.10  mrg /* Size of _gcov_kvp_dynamic_pool array.  */
    724  1.1.1.10  mrg unsigned __gcov_kvp_dynamic_pool_size;
    725  1.1.1.10  mrg 
    726   1.1.1.4  mrg void
    727   1.1.1.4  mrg __gcov_exit (void)
    728       1.1  mrg {
    729       1.1  mrg   __gcov_dump_one (&__gcov_root);
    730       1.1  mrg   if (__gcov_root.next)
    731       1.1  mrg     __gcov_root.next->prev = __gcov_root.prev;
    732       1.1  mrg   if (__gcov_root.prev)
    733       1.1  mrg     __gcov_root.prev->next = __gcov_root.next;
    734       1.1  mrg   else
    735       1.1  mrg     __gcov_master.root = __gcov_root.next;
    736   1.1.1.4  mrg 
    737   1.1.1.4  mrg   gcov_error_exit ();
    738       1.1  mrg }
    739       1.1  mrg 
    740       1.1  mrg /* Add a new object file onto the bb chain.  Invoked automatically
    741       1.1  mrg   when running an object file's global ctors.  */
    742       1.1  mrg 
    743       1.1  mrg void
    744       1.1  mrg __gcov_init (struct gcov_info *info)
    745       1.1  mrg {
    746       1.1  mrg   if (!info->version || !info->n_functions)
    747       1.1  mrg     return;
    748       1.1  mrg   if (gcov_version (info, info->version, 0))
    749       1.1  mrg     {
    750       1.1  mrg       if (!__gcov_root.list)
    751       1.1  mrg 	{
    752       1.1  mrg 	  /* Add to master list and at exit function.  */
    753       1.1  mrg 	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
    754       1.1  mrg 	    {
    755       1.1  mrg 	      __gcov_root.next = __gcov_master.root;
    756       1.1  mrg 	      if (__gcov_master.root)
    757       1.1  mrg 		__gcov_master.root->prev = &__gcov_root;
    758       1.1  mrg 	      __gcov_master.root = &__gcov_root;
    759       1.1  mrg 	    }
    760       1.1  mrg 	}
    761       1.1  mrg 
    762       1.1  mrg       info->next = __gcov_root.list;
    763       1.1  mrg       __gcov_root.list = info;
    764       1.1  mrg     }
    765       1.1  mrg }
    766       1.1  mrg #endif /* !IN_GCOV_TOOL */
    767  1.1.1.10  mrg #endif /* NEED_L_GCOV */
    768  1.1.1.10  mrg 
    769  1.1.1.10  mrg #ifdef NEED_L_GCOV_INFO_TO_GCDA
    770  1.1.1.10  mrg /* Convert the gcov info to a gcda data stream.  It is intended for
    771  1.1.1.10  mrg    free-standing environments which do not support the C library file I/O.  */
    772  1.1.1.10  mrg 
    773  1.1.1.10  mrg void
    774  1.1.1.10  mrg __gcov_info_to_gcda (const struct gcov_info *gi_ptr,
    775  1.1.1.10  mrg 		     void (*filename_fn) (const char *, void *),
    776  1.1.1.10  mrg 		     void (*dump_fn) (const void *, unsigned, void *),
    777  1.1.1.10  mrg 		     void *(*allocate_fn) (unsigned, void *),
    778  1.1.1.10  mrg 		     void *arg)
    779  1.1.1.10  mrg {
    780  1.1.1.10  mrg   (*filename_fn) (gi_ptr->filename, arg);
    781  1.1.1.10  mrg   write_one_data (gi_ptr, NULL, dump_fn, allocate_fn, arg);
    782  1.1.1.10  mrg }
    783  1.1.1.10  mrg #endif /* NEED_L_GCOV_INFO_TO_GCDA */
    784