Home | History | Annotate | Line # | Download | only in libgcc
libgcov-driver.c revision 1.6
      1  1.1  mrg /* Routines required for instrumenting a program.  */
      2  1.1  mrg /* Compile this one with gcc.  */
      3  1.6  mrg /* Copyright (C) 1989-2020 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.5  mrg #include "gcov-io.h"
     28  1.1  mrg 
     29  1.1  mrg #if defined(inhibit_libc)
     30  1.1  mrg /* If libc and its header files are not available, provide dummy functions.  */
     31  1.1  mrg 
     32  1.1  mrg #if defined(L_gcov)
     33  1.1  mrg void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
     34  1.1  mrg #endif
     35  1.1  mrg 
     36  1.1  mrg #else /* inhibit_libc */
     37  1.1  mrg 
     38  1.1  mrg #include <string.h>
     39  1.1  mrg #if GCOV_LOCKED
     40  1.1  mrg #include <fcntl.h>
     41  1.1  mrg #include <errno.h>
     42  1.1  mrg #include <sys/stat.h>
     43  1.1  mrg #endif
     44  1.1  mrg 
     45  1.1  mrg #ifdef L_gcov
     46  1.1  mrg 
     47  1.3  mrg /* A utility function for outputting errors.  */
     48  1.1  mrg static int gcov_error (const char *, ...);
     49  1.1  mrg 
     50  1.3  mrg #if !IN_GCOV_TOOL
     51  1.3  mrg static void gcov_error_exit (void);
     52  1.3  mrg #endif
     53  1.3  mrg 
     54  1.1  mrg #include "gcov-io.c"
     55  1.1  mrg 
     56  1.5  mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
     57  1.5  mrg 
     58  1.1  mrg struct gcov_fn_buffer
     59  1.1  mrg {
     60  1.1  mrg   struct gcov_fn_buffer *next;
     61  1.1  mrg   unsigned fn_ix;
     62  1.1  mrg   struct gcov_fn_info info;
     63  1.1  mrg   /* note gcov_fn_info ends in a trailing array.  */
     64  1.1  mrg };
     65  1.1  mrg 
     66  1.1  mrg struct gcov_summary_buffer
     67  1.1  mrg {
     68  1.1  mrg   struct gcov_summary_buffer *next;
     69  1.1  mrg   struct gcov_summary summary;
     70  1.1  mrg };
     71  1.1  mrg 
     72  1.1  mrg /* A struct that bundles all the related information about the
     73  1.1  mrg    gcda filename.  */
     74  1.1  mrg 
     75  1.1  mrg struct gcov_filename
     76  1.1  mrg {
     77  1.1  mrg   char *filename;  /* filename buffer */
     78  1.1  mrg   int strip; /* leading chars to strip from filename */
     79  1.5  mrg   char *prefix; /* prefix string */
     80  1.1  mrg };
     81  1.1  mrg 
     82  1.1  mrg static struct gcov_fn_buffer *
     83  1.1  mrg free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
     84  1.1  mrg               unsigned limit)
     85  1.1  mrg {
     86  1.1  mrg   struct gcov_fn_buffer *next;
     87  1.1  mrg   unsigned ix, n_ctr = 0;
     88  1.1  mrg 
     89  1.1  mrg   if (!buffer)
     90  1.1  mrg     return 0;
     91  1.1  mrg   next = buffer->next;
     92  1.1  mrg 
     93  1.1  mrg   for (ix = 0; ix != limit; ix++)
     94  1.1  mrg     if (gi_ptr->merge[ix])
     95  1.1  mrg       free (buffer->info.ctrs[n_ctr++].values);
     96  1.1  mrg   free (buffer);
     97  1.1  mrg   return next;
     98  1.1  mrg }
     99  1.1  mrg 
    100  1.1  mrg static struct gcov_fn_buffer **
    101  1.1  mrg buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
    102  1.1  mrg                 struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
    103  1.1  mrg {
    104  1.1  mrg   unsigned n_ctrs = 0, ix = 0;
    105  1.1  mrg   struct gcov_fn_buffer *fn_buffer;
    106  1.1  mrg   unsigned len;
    107  1.1  mrg 
    108  1.1  mrg   for (ix = GCOV_COUNTERS; ix--;)
    109  1.1  mrg     if (gi_ptr->merge[ix])
    110  1.1  mrg       n_ctrs++;
    111  1.1  mrg 
    112  1.1  mrg   len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
    113  1.1  mrg   fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
    114  1.1  mrg 
    115  1.1  mrg   if (!fn_buffer)
    116  1.1  mrg     goto fail;
    117  1.1  mrg 
    118  1.1  mrg   fn_buffer->next = 0;
    119  1.1  mrg   fn_buffer->fn_ix = fn_ix;
    120  1.1  mrg   fn_buffer->info.ident = gcov_read_unsigned ();
    121  1.1  mrg   fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
    122  1.1  mrg   fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
    123  1.1  mrg 
    124  1.1  mrg   for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
    125  1.1  mrg     {
    126  1.1  mrg       gcov_unsigned_t length;
    127  1.1  mrg       gcov_type *values;
    128  1.1  mrg 
    129  1.1  mrg       if (!gi_ptr->merge[ix])
    130  1.1  mrg         continue;
    131  1.1  mrg 
    132  1.1  mrg       if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
    133  1.1  mrg         {
    134  1.1  mrg           len = 0;
    135  1.1  mrg           goto fail;
    136  1.1  mrg         }
    137  1.1  mrg 
    138  1.1  mrg       length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
    139  1.1  mrg       len = length * sizeof (gcov_type);
    140  1.1  mrg       values = (gcov_type *) xmalloc (len);
    141  1.1  mrg       if (!values)
    142  1.1  mrg         goto fail;
    143  1.1  mrg 
    144  1.1  mrg       fn_buffer->info.ctrs[n_ctrs].num = length;
    145  1.1  mrg       fn_buffer->info.ctrs[n_ctrs].values = values;
    146  1.1  mrg 
    147  1.1  mrg       while (length--)
    148  1.1  mrg         *values++ = gcov_read_counter ();
    149  1.1  mrg       n_ctrs++;
    150  1.1  mrg     }
    151  1.1  mrg 
    152  1.1  mrg   *end_ptr = fn_buffer;
    153  1.1  mrg   return &fn_buffer->next;
    154  1.1  mrg 
    155  1.1  mrg fail:
    156  1.5  mrg   gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
    157  1.1  mrg               len ? "cannot allocate" : "counter mismatch", len ? len : ix);
    158  1.1  mrg 
    159  1.1  mrg   return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
    160  1.1  mrg }
    161  1.1  mrg 
    162  1.5  mrg /* Convert VERSION into a string description and return the it.
    163  1.5  mrg    BUFFER is used for storage of the string.  The code should be
    164  1.5  mrg    aligned wit gcov-iov.c.  */
    165  1.5  mrg 
    166  1.5  mrg static char *
    167  1.5  mrg gcov_version_string (char *buffer, char version[4])
    168  1.5  mrg {
    169  1.5  mrg   if (version[0] < 'A' || version[0] > 'Z'
    170  1.5  mrg       || version[1] < '0' || version[1] > '9'
    171  1.5  mrg       || version[2] < '0' || version[2] > '9')
    172  1.5  mrg     sprintf (buffer, "(unknown)");
    173  1.5  mrg   else
    174  1.1  mrg     {
    175  1.5  mrg       unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
    176  1.5  mrg       unsigned minor = version[2] - '0';
    177  1.5  mrg       sprintf (buffer, "%u.%u (%s)", major, minor,
    178  1.5  mrg 	       version[3] == '*' ? "release" : "experimental");
    179  1.1  mrg     }
    180  1.5  mrg   return buffer;
    181  1.1  mrg }
    182  1.1  mrg 
    183  1.1  mrg /* Check if VERSION of the info block PTR matches libgcov one.
    184  1.1  mrg    Return 1 on success, or zero in case of versions mismatch.
    185  1.1  mrg    If FILENAME is not NULL, its value used for reporting purposes
    186  1.1  mrg    instead of value from the info block.  */
    187  1.1  mrg 
    188  1.1  mrg static int
    189  1.1  mrg gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
    190  1.1  mrg               const char *filename)
    191  1.1  mrg {
    192  1.1  mrg   if (version != GCOV_VERSION)
    193  1.1  mrg     {
    194  1.1  mrg       char v[4], e[4];
    195  1.5  mrg       char version_string[128], expected_string[128];
    196  1.1  mrg 
    197  1.1  mrg       GCOV_UNSIGNED2STRING (v, version);
    198  1.1  mrg       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
    199  1.1  mrg 
    200  1.5  mrg       gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
    201  1.5  mrg 		  "got %s (%.4s)\n",
    202  1.5  mrg 		  filename? filename : ptr->filename,
    203  1.5  mrg 		  gcov_version_string (expected_string, e), e,
    204  1.5  mrg 		  gcov_version_string (version_string, v), v);
    205  1.1  mrg       return 0;
    206  1.1  mrg     }
    207  1.1  mrg   return 1;
    208  1.1  mrg }
    209  1.1  mrg 
    210  1.1  mrg /* buffer for the fn_data from another program.  */
    211  1.1  mrg static struct gcov_fn_buffer *fn_buffer;
    212  1.1  mrg 
    213  1.1  mrg /* Including system dependent components. */
    214  1.1  mrg #include "libgcov-driver-system.c"
    215  1.1  mrg 
    216  1.6  mrg /* Prune TOP N value COUNTERS.  It's needed in order to preserve
    217  1.6  mrg    reproducibility of builds.  */
    218  1.6  mrg 
    219  1.6  mrg static void
    220  1.6  mrg prune_topn_counter (gcov_type *counters, gcov_type all)
    221  1.6  mrg {
    222  1.6  mrg   for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
    223  1.6  mrg     if (counters[2 * i + 1] < all)
    224  1.6  mrg       {
    225  1.6  mrg 	counters[2 * i] = 0;
    226  1.6  mrg 	counters[2 * i + 1] = 0;
    227  1.6  mrg       }
    228  1.6  mrg }
    229  1.6  mrg 
    230  1.6  mrg /* Prune counters so that they are ready to store or merge.  */
    231  1.6  mrg 
    232  1.6  mrg static void
    233  1.6  mrg prune_counters (struct gcov_info *gi)
    234  1.6  mrg {
    235  1.6  mrg   for (unsigned i = 0; i < gi->n_functions; i++)
    236  1.6  mrg     {
    237  1.6  mrg       const struct gcov_fn_info *gfi = gi->functions[i];
    238  1.6  mrg       const struct gcov_ctr_info *ci = gfi->ctrs;
    239  1.6  mrg 
    240  1.6  mrg       for (unsigned j = 0; j < GCOV_COUNTERS; j++)
    241  1.6  mrg 	{
    242  1.6  mrg 	  if (gi->merge[j] == NULL)
    243  1.6  mrg 	    continue;
    244  1.6  mrg 
    245  1.6  mrg 	  if (j == GCOV_COUNTER_V_TOPN || j == GCOV_COUNTER_V_INDIR)
    246  1.6  mrg 	    {
    247  1.6  mrg 	      gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS));
    248  1.6  mrg 	      for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS);
    249  1.6  mrg 		   k++)
    250  1.6  mrg 		{
    251  1.6  mrg 		  gcov_type *counters
    252  1.6  mrg 		    = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS);
    253  1.6  mrg 		  prune_topn_counter (counters + 1, *counters);
    254  1.6  mrg 		}
    255  1.6  mrg 	    }
    256  1.6  mrg 	  ci++;
    257  1.6  mrg 	}
    258  1.6  mrg     }
    259  1.6  mrg }
    260  1.6  mrg 
    261  1.1  mrg /* This function merges counters in GI_PTR to an existing gcda file.
    262  1.1  mrg    Return 0 on success.
    263  1.1  mrg    Return -1 on error. In this case, caller will goto read_fatal.  */
    264  1.1  mrg 
    265  1.1  mrg static int
    266  1.1  mrg merge_one_data (const char *filename,
    267  1.1  mrg 		struct gcov_info *gi_ptr,
    268  1.5  mrg 		struct gcov_summary *summary)
    269  1.1  mrg {
    270  1.1  mrg   gcov_unsigned_t tag, length;
    271  1.1  mrg   unsigned t_ix;
    272  1.5  mrg   int f_ix = -1;
    273  1.1  mrg   int error = 0;
    274  1.1  mrg   struct gcov_fn_buffer **fn_tail = &fn_buffer;
    275  1.1  mrg 
    276  1.1  mrg   length = gcov_read_unsigned ();
    277  1.1  mrg   if (!gcov_version (gi_ptr, length, filename))
    278  1.1  mrg     return -1;
    279  1.1  mrg 
    280  1.1  mrg   length = gcov_read_unsigned ();
    281  1.1  mrg   if (length != gi_ptr->stamp)
    282  1.1  mrg     {
    283  1.5  mrg       /* Read from a different compilation.  Overwrite the file.  */
    284  1.5  mrg       gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
    285  1.5  mrg 		  "with a different timestamp\n", filename);
    286  1.5  mrg       return 0;
    287  1.5  mrg     }
    288  1.1  mrg 
    289  1.5  mrg   tag = gcov_read_unsigned ();
    290  1.5  mrg   if (tag != GCOV_TAG_OBJECT_SUMMARY)
    291  1.5  mrg     goto read_mismatch;
    292  1.5  mrg   length = gcov_read_unsigned ();
    293  1.5  mrg   gcc_assert (length > 0);
    294  1.5  mrg   gcov_read_summary (summary);
    295  1.1  mrg 
    296  1.5  mrg   tag = gcov_read_unsigned ();
    297  1.1  mrg   /* Merge execution counts for each function.  */
    298  1.1  mrg   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
    299  1.1  mrg        f_ix++, tag = gcov_read_unsigned ())
    300  1.1  mrg     {
    301  1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    302  1.1  mrg       const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
    303  1.1  mrg 
    304  1.1  mrg       if (tag != GCOV_TAG_FUNCTION)
    305  1.1  mrg         goto read_mismatch;
    306  1.1  mrg 
    307  1.1  mrg       length = gcov_read_unsigned ();
    308  1.1  mrg       if (!length)
    309  1.1  mrg         /* This function did not appear in the other program.
    310  1.1  mrg            We have nothing to merge.  */
    311  1.1  mrg         continue;
    312  1.1  mrg 
    313  1.1  mrg       if (length != GCOV_TAG_FUNCTION_LENGTH)
    314  1.1  mrg         goto read_mismatch;
    315  1.1  mrg 
    316  1.1  mrg       if (!gfi_ptr || gfi_ptr->key != gi_ptr)
    317  1.1  mrg         {
    318  1.1  mrg           /* This function appears in the other program.  We
    319  1.1  mrg              need to buffer the information in order to write
    320  1.1  mrg              it back out -- we'll be inserting data before
    321  1.1  mrg              this point, so cannot simply keep the data in the
    322  1.1  mrg              file.  */
    323  1.1  mrg           fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
    324  1.1  mrg           if (!fn_tail)
    325  1.1  mrg             goto read_mismatch;
    326  1.1  mrg           continue;
    327  1.1  mrg         }
    328  1.1  mrg 
    329  1.1  mrg       length = gcov_read_unsigned ();
    330  1.1  mrg       if (length != gfi_ptr->ident)
    331  1.1  mrg         goto read_mismatch;
    332  1.1  mrg 
    333  1.1  mrg       length = gcov_read_unsigned ();
    334  1.1  mrg       if (length != gfi_ptr->lineno_checksum)
    335  1.1  mrg         goto read_mismatch;
    336  1.1  mrg 
    337  1.1  mrg       length = gcov_read_unsigned ();
    338  1.1  mrg       if (length != gfi_ptr->cfg_checksum)
    339  1.1  mrg         goto read_mismatch;
    340  1.1  mrg 
    341  1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    342  1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    343  1.1  mrg         {
    344  1.1  mrg           gcov_merge_fn merge = gi_ptr->merge[t_ix];
    345  1.1  mrg 
    346  1.1  mrg           if (!merge)
    347  1.1  mrg             continue;
    348  1.1  mrg 
    349  1.1  mrg           tag = gcov_read_unsigned ();
    350  1.1  mrg           length = gcov_read_unsigned ();
    351  1.1  mrg           if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
    352  1.1  mrg               || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
    353  1.1  mrg             goto read_mismatch;
    354  1.1  mrg           (*merge) (ci_ptr->values, ci_ptr->num);
    355  1.1  mrg           ci_ptr++;
    356  1.1  mrg         }
    357  1.1  mrg       if ((error = gcov_is_error ()))
    358  1.1  mrg         goto read_error;
    359  1.1  mrg     }
    360  1.1  mrg 
    361  1.1  mrg   if (tag)
    362  1.1  mrg     {
    363  1.1  mrg     read_mismatch:;
    364  1.5  mrg       gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
    365  1.1  mrg                   filename, f_ix >= 0 ? "function" : "summary",
    366  1.1  mrg                   f_ix < 0 ? -1 - f_ix : f_ix);
    367  1.1  mrg       return -1;
    368  1.1  mrg     }
    369  1.1  mrg   return 0;
    370  1.1  mrg 
    371  1.1  mrg read_error:
    372  1.5  mrg   gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
    373  1.1  mrg               error < 0 ? "Overflow": "Error");
    374  1.1  mrg   return -1;
    375  1.1  mrg }
    376  1.1  mrg 
    377  1.1  mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
    378  1.1  mrg    the case of appending to an existing file, SUMMARY_POS will be non-zero.
    379  1.1  mrg    We will write the file starting from SUMMAY_POS.  */
    380  1.1  mrg 
    381  1.1  mrg static void
    382  1.1  mrg write_one_data (const struct gcov_info *gi_ptr,
    383  1.5  mrg 		const struct gcov_summary *prg_p)
    384  1.1  mrg {
    385  1.1  mrg   unsigned f_ix;
    386  1.1  mrg 
    387  1.5  mrg   gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
    388  1.5  mrg   gcov_write_unsigned (gi_ptr->stamp);
    389  1.1  mrg 
    390  1.1  mrg   /* Generate whole program statistics.  */
    391  1.5  mrg   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
    392  1.1  mrg 
    393  1.1  mrg   /* Write execution counts for each function.  */
    394  1.1  mrg   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
    395  1.1  mrg     {
    396  1.1  mrg       unsigned buffered = 0;
    397  1.1  mrg       const struct gcov_fn_info *gfi_ptr;
    398  1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    399  1.1  mrg       gcov_unsigned_t length;
    400  1.1  mrg       unsigned t_ix;
    401  1.1  mrg 
    402  1.1  mrg       if (fn_buffer && fn_buffer->fn_ix == f_ix)
    403  1.1  mrg         {
    404  1.1  mrg           /* Buffered data from another program.  */
    405  1.1  mrg           buffered = 1;
    406  1.1  mrg           gfi_ptr = &fn_buffer->info;
    407  1.1  mrg           length = GCOV_TAG_FUNCTION_LENGTH;
    408  1.1  mrg         }
    409  1.1  mrg       else
    410  1.1  mrg         {
    411  1.1  mrg           gfi_ptr = gi_ptr->functions[f_ix];
    412  1.1  mrg           if (gfi_ptr && gfi_ptr->key == gi_ptr)
    413  1.1  mrg             length = GCOV_TAG_FUNCTION_LENGTH;
    414  1.1  mrg           else
    415  1.1  mrg                 length = 0;
    416  1.1  mrg         }
    417  1.1  mrg 
    418  1.1  mrg       gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
    419  1.1  mrg       if (!length)
    420  1.1  mrg         continue;
    421  1.1  mrg 
    422  1.1  mrg       gcov_write_unsigned (gfi_ptr->ident);
    423  1.1  mrg       gcov_write_unsigned (gfi_ptr->lineno_checksum);
    424  1.1  mrg       gcov_write_unsigned (gfi_ptr->cfg_checksum);
    425  1.1  mrg 
    426  1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    427  1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    428  1.1  mrg         {
    429  1.1  mrg           gcov_unsigned_t n_counts;
    430  1.1  mrg           gcov_type *c_ptr;
    431  1.1  mrg 
    432  1.1  mrg           if (!gi_ptr->merge[t_ix])
    433  1.1  mrg             continue;
    434  1.1  mrg 
    435  1.1  mrg           n_counts = ci_ptr->num;
    436  1.1  mrg           gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
    437  1.1  mrg                                  GCOV_TAG_COUNTER_LENGTH (n_counts));
    438  1.1  mrg           c_ptr = ci_ptr->values;
    439  1.1  mrg           while (n_counts--)
    440  1.1  mrg             gcov_write_counter (*c_ptr++);
    441  1.1  mrg           ci_ptr++;
    442  1.1  mrg         }
    443  1.1  mrg       if (buffered)
    444  1.1  mrg         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    445  1.1  mrg     }
    446  1.1  mrg 
    447  1.1  mrg   gcov_write_unsigned (0);
    448  1.1  mrg }
    449  1.1  mrg 
    450  1.5  mrg /* Helper function for merging summary.  */
    451  1.1  mrg 
    452  1.5  mrg static void
    453  1.5  mrg merge_summary (int run_counted, struct gcov_summary *summary,
    454  1.5  mrg 	      gcov_type run_max)
    455  1.1  mrg {
    456  1.5  mrg   if (!run_counted)
    457  1.1  mrg     {
    458  1.5  mrg       summary->runs++;
    459  1.5  mrg       summary->sum_max += run_max;
    460  1.1  mrg     }
    461  1.1  mrg }
    462  1.1  mrg 
    463  1.1  mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
    464  1.1  mrg    counts when possible, to avoid growing the .da files ad infinitum. We use
    465  1.1  mrg    this program's checksum to make sure we only accumulate whole program
    466  1.1  mrg    statistics to the correct summary. An object file might be embedded
    467  1.1  mrg    in two separate programs, and we must keep the two program
    468  1.1  mrg    summaries separate.  */
    469  1.1  mrg 
    470  1.1  mrg static void
    471  1.1  mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
    472  1.5  mrg 	       unsigned run_counted, gcov_type run_max)
    473  1.1  mrg {
    474  1.5  mrg   struct gcov_summary summary = {};
    475  1.1  mrg   int error;
    476  1.1  mrg   gcov_unsigned_t tag;
    477  1.1  mrg   fn_buffer = 0;
    478  1.1  mrg 
    479  1.6  mrg   /* Prune current counters before we merge them.  */
    480  1.6  mrg   prune_counters (gi_ptr);
    481  1.1  mrg 
    482  1.1  mrg   error = gcov_exit_open_gcda_file (gi_ptr, gf);
    483  1.1  mrg   if (error == -1)
    484  1.1  mrg     return;
    485  1.1  mrg 
    486  1.1  mrg   tag = gcov_read_unsigned ();
    487  1.1  mrg   if (tag)
    488  1.1  mrg     {
    489  1.1  mrg       /* Merge data from file.  */
    490  1.1  mrg       if (tag != GCOV_DATA_MAGIC)
    491  1.1  mrg         {
    492  1.5  mrg 	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
    493  1.5  mrg 		      gf->filename);
    494  1.1  mrg           goto read_fatal;
    495  1.1  mrg         }
    496  1.5  mrg       error = merge_one_data (gf->filename, gi_ptr, &summary);
    497  1.1  mrg       if (error == -1)
    498  1.1  mrg         goto read_fatal;
    499  1.1  mrg     }
    500  1.1  mrg 
    501  1.1  mrg   gcov_rewrite ();
    502  1.1  mrg 
    503  1.5  mrg   merge_summary (run_counted, &summary, run_max);
    504  1.1  mrg 
    505  1.5  mrg   write_one_data (gi_ptr, &summary);
    506  1.1  mrg   /* fall through */
    507  1.1  mrg 
    508  1.1  mrg read_fatal:;
    509  1.1  mrg   while (fn_buffer)
    510  1.1  mrg     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    511  1.1  mrg 
    512  1.1  mrg   if ((error = gcov_close ()))
    513  1.1  mrg     gcov_error (error  < 0 ?
    514  1.5  mrg 		GCOV_PROF_PREFIX "Overflow writing\n" :
    515  1.5  mrg 		GCOV_PROF_PREFIX "Error writing\n",
    516  1.1  mrg                 gf->filename);
    517  1.1  mrg }
    518  1.1  mrg 
    519  1.1  mrg 
    520  1.1  mrg /* Dump all the coverage counts for the program. It first computes program
    521  1.1  mrg    summary and then traverses gcov_list list and dumps the gcov_info
    522  1.1  mrg    objects one by one.  */
    523  1.1  mrg 
    524  1.1  mrg #if !IN_GCOV_TOOL
    525  1.1  mrg static
    526  1.1  mrg #endif
    527  1.1  mrg void
    528  1.1  mrg gcov_do_dump (struct gcov_info *list, int run_counted)
    529  1.1  mrg {
    530  1.1  mrg   struct gcov_info *gi_ptr;
    531  1.1  mrg   struct gcov_filename gf;
    532  1.1  mrg 
    533  1.5  mrg   /* Compute run_max of this program run.  */
    534  1.5  mrg   gcov_type run_max = 0;
    535  1.5  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    536  1.5  mrg     for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
    537  1.5  mrg       {
    538  1.5  mrg 	const struct gcov_ctr_info *cinfo
    539  1.5  mrg 	  = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
    540  1.5  mrg 
    541  1.5  mrg 	for (unsigned i = 0; i < cinfo->num; i++)
    542  1.5  mrg 	  if (run_max < cinfo->values[i])
    543  1.5  mrg 	    run_max = cinfo->values[i];
    544  1.5  mrg       }
    545  1.1  mrg 
    546  1.1  mrg   allocate_filename_struct (&gf);
    547  1.1  mrg 
    548  1.1  mrg   /* Now merge each file.  */
    549  1.1  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    550  1.5  mrg     {
    551  1.5  mrg       dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
    552  1.5  mrg       free (gf.filename);
    553  1.5  mrg     }
    554  1.1  mrg 
    555  1.5  mrg   free (gf.prefix);
    556  1.1  mrg }
    557  1.1  mrg 
    558  1.3  mrg #if IN_GCOV_TOOL
    559  1.3  mrg const char *
    560  1.3  mrg __attribute__ ((unused))
    561  1.3  mrg gcov_get_filename (struct gcov_info *list)
    562  1.3  mrg {
    563  1.3  mrg   return list->filename;
    564  1.3  mrg }
    565  1.3  mrg #endif
    566  1.3  mrg 
    567  1.1  mrg #if !IN_GCOV_TOOL
    568  1.1  mrg void
    569  1.1  mrg __gcov_dump_one (struct gcov_root *root)
    570  1.1  mrg {
    571  1.1  mrg   if (root->dumped)
    572  1.1  mrg     return;
    573  1.1  mrg 
    574  1.1  mrg   gcov_do_dump (root->list, root->run_counted);
    575  1.1  mrg 
    576  1.1  mrg   root->dumped = 1;
    577  1.1  mrg   root->run_counted = 1;
    578  1.1  mrg }
    579  1.1  mrg 
    580  1.1  mrg /* Per-dynamic-object gcov state.  */
    581  1.1  mrg struct gcov_root __gcov_root;
    582  1.1  mrg 
    583  1.1  mrg /* Exactly one of these will be live in the process image.  */
    584  1.1  mrg struct gcov_master __gcov_master =
    585  1.1  mrg   {GCOV_VERSION, 0};
    586  1.1  mrg 
    587  1.3  mrg void
    588  1.3  mrg __gcov_exit (void)
    589  1.1  mrg {
    590  1.1  mrg   __gcov_dump_one (&__gcov_root);
    591  1.1  mrg   if (__gcov_root.next)
    592  1.1  mrg     __gcov_root.next->prev = __gcov_root.prev;
    593  1.1  mrg   if (__gcov_root.prev)
    594  1.1  mrg     __gcov_root.prev->next = __gcov_root.next;
    595  1.1  mrg   else
    596  1.1  mrg     __gcov_master.root = __gcov_root.next;
    597  1.3  mrg 
    598  1.3  mrg   gcov_error_exit ();
    599  1.1  mrg }
    600  1.1  mrg 
    601  1.1  mrg /* Add a new object file onto the bb chain.  Invoked automatically
    602  1.1  mrg   when running an object file's global ctors.  */
    603  1.1  mrg 
    604  1.1  mrg void
    605  1.1  mrg __gcov_init (struct gcov_info *info)
    606  1.1  mrg {
    607  1.1  mrg   if (!info->version || !info->n_functions)
    608  1.1  mrg     return;
    609  1.1  mrg   if (gcov_version (info, info->version, 0))
    610  1.1  mrg     {
    611  1.1  mrg       if (!__gcov_root.list)
    612  1.1  mrg 	{
    613  1.1  mrg 	  /* Add to master list and at exit function.  */
    614  1.1  mrg 	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
    615  1.1  mrg 	    {
    616  1.1  mrg 	      __gcov_root.next = __gcov_master.root;
    617  1.1  mrg 	      if (__gcov_master.root)
    618  1.1  mrg 		__gcov_master.root->prev = &__gcov_root;
    619  1.1  mrg 	      __gcov_master.root = &__gcov_root;
    620  1.1  mrg 	    }
    621  1.1  mrg 	}
    622  1.1  mrg 
    623  1.1  mrg       info->next = __gcov_root.list;
    624  1.1  mrg       __gcov_root.list = info;
    625  1.1  mrg     }
    626  1.1  mrg }
    627  1.1  mrg #endif /* !IN_GCOV_TOOL */
    628  1.1  mrg #endif /* L_gcov */
    629  1.1  mrg #endif /* inhibit_libc */
    630