Home | History | Annotate | Line # | Download | only in libgcc
libgcov-driver.c revision 1.1.1.8
      1      1.1  mrg /* Routines required for instrumenting a program.  */
      2      1.1  mrg /* Compile this one with gcc.  */
      3  1.1.1.8  mrg /* Copyright (C) 1989-2019 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  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.1.1.4  mrg /* A utility function for outputting errors.  */
     48      1.1  mrg static int gcov_error (const char *, ...);
     49      1.1  mrg 
     50  1.1.1.4  mrg #if !IN_GCOV_TOOL
     51  1.1.1.4  mrg static void gcov_error_exit (void);
     52  1.1.1.4  mrg #endif
     53  1.1.1.4  mrg 
     54      1.1  mrg #include "gcov-io.c"
     55      1.1  mrg 
     56  1.1.1.8  mrg #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
     57  1.1.1.8  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.1.1.8  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.1.1.8  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.1.1.8  mrg /* Convert VERSION into a string description and return the it.
    163  1.1.1.8  mrg    BUFFER is used for storage of the string.  The code should be
    164  1.1.1.8  mrg    aligned wit gcov-iov.c.  */
    165  1.1.1.8  mrg 
    166  1.1.1.8  mrg static char *
    167  1.1.1.8  mrg gcov_version_string (char *buffer, char version[4])
    168  1.1.1.8  mrg {
    169  1.1.1.8  mrg   if (version[0] < 'A' || version[0] > 'Z'
    170  1.1.1.8  mrg       || version[1] < '0' || version[1] > '9'
    171  1.1.1.8  mrg       || version[2] < '0' || version[2] > '9')
    172  1.1.1.8  mrg     sprintf (buffer, "(unknown)");
    173  1.1.1.8  mrg   else
    174      1.1  mrg     {
    175  1.1.1.8  mrg       unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
    176  1.1.1.8  mrg       unsigned minor = version[2] - '0';
    177  1.1.1.8  mrg       sprintf (buffer, "%u.%u (%s)", major, minor,
    178  1.1.1.8  mrg 	       version[3] == '*' ? "release" : "experimental");
    179      1.1  mrg     }
    180  1.1.1.8  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.1.1.8  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.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
    201  1.1.1.8  mrg 		  "got %s (%.4s)\n",
    202  1.1.1.8  mrg 		  filename? filename : ptr->filename,
    203  1.1.1.8  mrg 		  gcov_version_string (expected_string, e), e,
    204  1.1.1.8  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.1  mrg /* This function merges counters in GI_PTR to an existing gcda file.
    217      1.1  mrg    Return 0 on success.
    218      1.1  mrg    Return -1 on error. In this case, caller will goto read_fatal.  */
    219      1.1  mrg 
    220      1.1  mrg static int
    221      1.1  mrg merge_one_data (const char *filename,
    222      1.1  mrg 		struct gcov_info *gi_ptr,
    223  1.1.1.8  mrg 		struct gcov_summary *summary)
    224      1.1  mrg {
    225      1.1  mrg   gcov_unsigned_t tag, length;
    226      1.1  mrg   unsigned t_ix;
    227  1.1.1.8  mrg   int f_ix = -1;
    228      1.1  mrg   int error = 0;
    229      1.1  mrg   struct gcov_fn_buffer **fn_tail = &fn_buffer;
    230      1.1  mrg 
    231      1.1  mrg   length = gcov_read_unsigned ();
    232      1.1  mrg   if (!gcov_version (gi_ptr, length, filename))
    233      1.1  mrg     return -1;
    234      1.1  mrg 
    235      1.1  mrg   length = gcov_read_unsigned ();
    236      1.1  mrg   if (length != gi_ptr->stamp)
    237      1.1  mrg     {
    238  1.1.1.8  mrg       /* Read from a different compilation.  Overwrite the file.  */
    239  1.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
    240  1.1.1.8  mrg 		  "with a different timestamp\n", filename);
    241  1.1.1.8  mrg       return 0;
    242      1.1  mrg     }
    243      1.1  mrg 
    244  1.1.1.8  mrg   tag = gcov_read_unsigned ();
    245  1.1.1.8  mrg   if (tag != GCOV_TAG_OBJECT_SUMMARY)
    246  1.1.1.8  mrg     goto read_mismatch;
    247  1.1.1.8  mrg   length = gcov_read_unsigned ();
    248  1.1.1.8  mrg   gcc_assert (length > 0);
    249  1.1.1.8  mrg   gcov_read_summary (summary);
    250  1.1.1.8  mrg 
    251  1.1.1.8  mrg   tag = gcov_read_unsigned ();
    252      1.1  mrg   /* Merge execution counts for each function.  */
    253      1.1  mrg   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
    254      1.1  mrg        f_ix++, tag = gcov_read_unsigned ())
    255      1.1  mrg     {
    256      1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    257      1.1  mrg       const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
    258      1.1  mrg 
    259      1.1  mrg       if (tag != GCOV_TAG_FUNCTION)
    260      1.1  mrg         goto read_mismatch;
    261      1.1  mrg 
    262      1.1  mrg       length = gcov_read_unsigned ();
    263      1.1  mrg       if (!length)
    264      1.1  mrg         /* This function did not appear in the other program.
    265      1.1  mrg            We have nothing to merge.  */
    266      1.1  mrg         continue;
    267      1.1  mrg 
    268      1.1  mrg       if (length != GCOV_TAG_FUNCTION_LENGTH)
    269      1.1  mrg         goto read_mismatch;
    270      1.1  mrg 
    271      1.1  mrg       if (!gfi_ptr || gfi_ptr->key != gi_ptr)
    272      1.1  mrg         {
    273      1.1  mrg           /* This function appears in the other program.  We
    274      1.1  mrg              need to buffer the information in order to write
    275      1.1  mrg              it back out -- we'll be inserting data before
    276      1.1  mrg              this point, so cannot simply keep the data in the
    277      1.1  mrg              file.  */
    278      1.1  mrg           fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
    279      1.1  mrg           if (!fn_tail)
    280      1.1  mrg             goto read_mismatch;
    281      1.1  mrg           continue;
    282      1.1  mrg         }
    283      1.1  mrg 
    284      1.1  mrg       length = gcov_read_unsigned ();
    285      1.1  mrg       if (length != gfi_ptr->ident)
    286      1.1  mrg         goto read_mismatch;
    287      1.1  mrg 
    288      1.1  mrg       length = gcov_read_unsigned ();
    289      1.1  mrg       if (length != gfi_ptr->lineno_checksum)
    290      1.1  mrg         goto read_mismatch;
    291      1.1  mrg 
    292      1.1  mrg       length = gcov_read_unsigned ();
    293      1.1  mrg       if (length != gfi_ptr->cfg_checksum)
    294      1.1  mrg         goto read_mismatch;
    295      1.1  mrg 
    296      1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    297      1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    298      1.1  mrg         {
    299      1.1  mrg           gcov_merge_fn merge = gi_ptr->merge[t_ix];
    300      1.1  mrg 
    301      1.1  mrg           if (!merge)
    302      1.1  mrg             continue;
    303      1.1  mrg 
    304      1.1  mrg           tag = gcov_read_unsigned ();
    305      1.1  mrg           length = gcov_read_unsigned ();
    306      1.1  mrg           if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
    307      1.1  mrg               || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
    308      1.1  mrg             goto read_mismatch;
    309      1.1  mrg           (*merge) (ci_ptr->values, ci_ptr->num);
    310      1.1  mrg           ci_ptr++;
    311      1.1  mrg         }
    312      1.1  mrg       if ((error = gcov_is_error ()))
    313      1.1  mrg         goto read_error;
    314      1.1  mrg     }
    315      1.1  mrg 
    316      1.1  mrg   if (tag)
    317      1.1  mrg     {
    318      1.1  mrg     read_mismatch:;
    319  1.1.1.8  mrg       gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
    320      1.1  mrg                   filename, f_ix >= 0 ? "function" : "summary",
    321      1.1  mrg                   f_ix < 0 ? -1 - f_ix : f_ix);
    322      1.1  mrg       return -1;
    323      1.1  mrg     }
    324      1.1  mrg   return 0;
    325      1.1  mrg 
    326      1.1  mrg read_error:
    327  1.1.1.8  mrg   gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
    328      1.1  mrg               error < 0 ? "Overflow": "Error");
    329      1.1  mrg   return -1;
    330      1.1  mrg }
    331      1.1  mrg 
    332      1.1  mrg /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
    333      1.1  mrg    the case of appending to an existing file, SUMMARY_POS will be non-zero.
    334      1.1  mrg    We will write the file starting from SUMMAY_POS.  */
    335      1.1  mrg 
    336      1.1  mrg static void
    337      1.1  mrg write_one_data (const struct gcov_info *gi_ptr,
    338  1.1.1.8  mrg 		const struct gcov_summary *prg_p)
    339      1.1  mrg {
    340      1.1  mrg   unsigned f_ix;
    341      1.1  mrg 
    342  1.1.1.8  mrg   gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
    343  1.1.1.8  mrg   gcov_write_unsigned (gi_ptr->stamp);
    344      1.1  mrg 
    345      1.1  mrg   /* Generate whole program statistics.  */
    346  1.1.1.8  mrg   gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, prg_p);
    347      1.1  mrg 
    348      1.1  mrg   /* Write execution counts for each function.  */
    349      1.1  mrg   for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
    350      1.1  mrg     {
    351      1.1  mrg       unsigned buffered = 0;
    352      1.1  mrg       const struct gcov_fn_info *gfi_ptr;
    353      1.1  mrg       const struct gcov_ctr_info *ci_ptr;
    354      1.1  mrg       gcov_unsigned_t length;
    355      1.1  mrg       unsigned t_ix;
    356      1.1  mrg 
    357      1.1  mrg       if (fn_buffer && fn_buffer->fn_ix == f_ix)
    358      1.1  mrg         {
    359      1.1  mrg           /* Buffered data from another program.  */
    360      1.1  mrg           buffered = 1;
    361      1.1  mrg           gfi_ptr = &fn_buffer->info;
    362      1.1  mrg           length = GCOV_TAG_FUNCTION_LENGTH;
    363      1.1  mrg         }
    364      1.1  mrg       else
    365      1.1  mrg         {
    366      1.1  mrg           gfi_ptr = gi_ptr->functions[f_ix];
    367      1.1  mrg           if (gfi_ptr && gfi_ptr->key == gi_ptr)
    368      1.1  mrg             length = GCOV_TAG_FUNCTION_LENGTH;
    369      1.1  mrg           else
    370      1.1  mrg                 length = 0;
    371      1.1  mrg         }
    372      1.1  mrg 
    373      1.1  mrg       gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
    374      1.1  mrg       if (!length)
    375      1.1  mrg         continue;
    376      1.1  mrg 
    377      1.1  mrg       gcov_write_unsigned (gfi_ptr->ident);
    378      1.1  mrg       gcov_write_unsigned (gfi_ptr->lineno_checksum);
    379      1.1  mrg       gcov_write_unsigned (gfi_ptr->cfg_checksum);
    380      1.1  mrg 
    381      1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    382      1.1  mrg       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
    383      1.1  mrg         {
    384      1.1  mrg           gcov_unsigned_t n_counts;
    385      1.1  mrg           gcov_type *c_ptr;
    386      1.1  mrg 
    387      1.1  mrg           if (!gi_ptr->merge[t_ix])
    388      1.1  mrg             continue;
    389      1.1  mrg 
    390      1.1  mrg           n_counts = ci_ptr->num;
    391      1.1  mrg           gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
    392      1.1  mrg                                  GCOV_TAG_COUNTER_LENGTH (n_counts));
    393      1.1  mrg           c_ptr = ci_ptr->values;
    394      1.1  mrg           while (n_counts--)
    395      1.1  mrg             gcov_write_counter (*c_ptr++);
    396      1.1  mrg           ci_ptr++;
    397      1.1  mrg         }
    398      1.1  mrg       if (buffered)
    399      1.1  mrg         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    400      1.1  mrg     }
    401      1.1  mrg 
    402      1.1  mrg   gcov_write_unsigned (0);
    403      1.1  mrg }
    404      1.1  mrg 
    405  1.1.1.8  mrg /* Helper function for merging summary.  */
    406      1.1  mrg 
    407  1.1.1.8  mrg static void
    408  1.1.1.8  mrg merge_summary (int run_counted, struct gcov_summary *summary,
    409  1.1.1.8  mrg 	      gcov_type run_max)
    410      1.1  mrg {
    411  1.1.1.8  mrg   if (!run_counted)
    412      1.1  mrg     {
    413  1.1.1.8  mrg       summary->runs++;
    414  1.1.1.8  mrg       summary->sum_max += run_max;
    415      1.1  mrg     }
    416      1.1  mrg }
    417      1.1  mrg 
    418      1.1  mrg /* Sort N entries in VALUE_ARRAY in descending order.
    419      1.1  mrg    Each entry in VALUE_ARRAY has two values. The sorting
    420      1.1  mrg    is based on the second value.  */
    421      1.1  mrg 
    422      1.1  mrg GCOV_LINKAGE  void
    423      1.1  mrg gcov_sort_n_vals (gcov_type *value_array, int n)
    424      1.1  mrg {
    425      1.1  mrg   int j, k;
    426      1.1  mrg 
    427      1.1  mrg   for (j = 2; j < n; j += 2)
    428      1.1  mrg     {
    429      1.1  mrg       gcov_type cur_ent[2];
    430      1.1  mrg 
    431      1.1  mrg       cur_ent[0] = value_array[j];
    432      1.1  mrg       cur_ent[1] = value_array[j + 1];
    433      1.1  mrg       k = j - 2;
    434      1.1  mrg       while (k >= 0 && value_array[k + 1] < cur_ent[1])
    435      1.1  mrg         {
    436      1.1  mrg           value_array[k + 2] = value_array[k];
    437      1.1  mrg           value_array[k + 3] = value_array[k+1];
    438      1.1  mrg           k -= 2;
    439      1.1  mrg         }
    440      1.1  mrg       value_array[k + 2] = cur_ent[0];
    441      1.1  mrg       value_array[k + 3] = cur_ent[1];
    442      1.1  mrg     }
    443      1.1  mrg }
    444      1.1  mrg 
    445      1.1  mrg /* Sort the profile counters for all indirect call sites. Counters
    446      1.1  mrg    for each call site are allocated in array COUNTERS.  */
    447      1.1  mrg 
    448      1.1  mrg static void
    449      1.1  mrg gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
    450      1.1  mrg {
    451      1.1  mrg   int i;
    452      1.1  mrg   gcov_type *values;
    453      1.1  mrg   int n = counters->num;
    454      1.1  mrg 
    455      1.1  mrg   gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
    456      1.1  mrg   values = counters->values;
    457      1.1  mrg 
    458      1.1  mrg   for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
    459      1.1  mrg     {
    460      1.1  mrg       gcov_type *value_array = &values[i + 1];
    461      1.1  mrg       gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
    462      1.1  mrg     }
    463      1.1  mrg }
    464      1.1  mrg 
    465      1.1  mrg /* Sort topn indirect_call profile counters in GI_PTR.  */
    466      1.1  mrg 
    467      1.1  mrg static void
    468      1.1  mrg gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
    469      1.1  mrg {
    470      1.1  mrg   unsigned int i;
    471      1.1  mrg   int f_ix;
    472      1.1  mrg   const struct gcov_fn_info *gfi_ptr;
    473      1.1  mrg   const struct gcov_ctr_info *ci_ptr;
    474      1.1  mrg 
    475      1.1  mrg   if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
    476      1.1  mrg     return;
    477      1.1  mrg 
    478      1.1  mrg   for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
    479      1.1  mrg     {
    480      1.1  mrg       gfi_ptr = gi_ptr->functions[f_ix];
    481      1.1  mrg       ci_ptr = gfi_ptr->ctrs;
    482      1.1  mrg       for (i = 0; i < GCOV_COUNTERS; i++)
    483      1.1  mrg         {
    484      1.1  mrg           if (!gi_ptr->merge[i])
    485      1.1  mrg             continue;
    486      1.1  mrg           if (i == GCOV_COUNTER_ICALL_TOPNV)
    487      1.1  mrg             {
    488      1.1  mrg               gcov_sort_icall_topn_counter (ci_ptr);
    489      1.1  mrg               break;
    490      1.1  mrg             }
    491      1.1  mrg           ci_ptr++;
    492      1.1  mrg         }
    493      1.1  mrg     }
    494      1.1  mrg }
    495      1.1  mrg 
    496      1.1  mrg /* Dump the coverage counts for one gcov_info object. We merge with existing
    497      1.1  mrg    counts when possible, to avoid growing the .da files ad infinitum. We use
    498      1.1  mrg    this program's checksum to make sure we only accumulate whole program
    499      1.1  mrg    statistics to the correct summary. An object file might be embedded
    500      1.1  mrg    in two separate programs, and we must keep the two program
    501      1.1  mrg    summaries separate.  */
    502      1.1  mrg 
    503      1.1  mrg static void
    504      1.1  mrg dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
    505  1.1.1.8  mrg 	       unsigned run_counted, gcov_type run_max)
    506      1.1  mrg {
    507  1.1.1.8  mrg   struct gcov_summary summary = {};
    508      1.1  mrg   int error;
    509      1.1  mrg   gcov_unsigned_t tag;
    510      1.1  mrg 
    511      1.1  mrg   fn_buffer = 0;
    512      1.1  mrg 
    513      1.1  mrg   gcov_sort_topn_counter_arrays (gi_ptr);
    514      1.1  mrg 
    515      1.1  mrg   error = gcov_exit_open_gcda_file (gi_ptr, gf);
    516      1.1  mrg   if (error == -1)
    517      1.1  mrg     return;
    518      1.1  mrg 
    519      1.1  mrg   tag = gcov_read_unsigned ();
    520      1.1  mrg   if (tag)
    521      1.1  mrg     {
    522      1.1  mrg       /* Merge data from file.  */
    523      1.1  mrg       if (tag != GCOV_DATA_MAGIC)
    524      1.1  mrg         {
    525  1.1.1.8  mrg 	  gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
    526  1.1.1.8  mrg 		      gf->filename);
    527      1.1  mrg           goto read_fatal;
    528      1.1  mrg         }
    529  1.1.1.8  mrg       error = merge_one_data (gf->filename, gi_ptr, &summary);
    530      1.1  mrg       if (error == -1)
    531      1.1  mrg         goto read_fatal;
    532      1.1  mrg     }
    533      1.1  mrg 
    534      1.1  mrg   gcov_rewrite ();
    535      1.1  mrg 
    536  1.1.1.8  mrg   merge_summary (run_counted, &summary, run_max);
    537      1.1  mrg 
    538  1.1.1.8  mrg   write_one_data (gi_ptr, &summary);
    539      1.1  mrg   /* fall through */
    540      1.1  mrg 
    541      1.1  mrg read_fatal:;
    542      1.1  mrg   while (fn_buffer)
    543      1.1  mrg     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
    544      1.1  mrg 
    545      1.1  mrg   if ((error = gcov_close ()))
    546      1.1  mrg     gcov_error (error  < 0 ?
    547  1.1.1.8  mrg 		GCOV_PROF_PREFIX "Overflow writing\n" :
    548  1.1.1.8  mrg 		GCOV_PROF_PREFIX "Error writing\n",
    549      1.1  mrg                 gf->filename);
    550      1.1  mrg }
    551      1.1  mrg 
    552      1.1  mrg 
    553      1.1  mrg /* Dump all the coverage counts for the program. It first computes program
    554      1.1  mrg    summary and then traverses gcov_list list and dumps the gcov_info
    555      1.1  mrg    objects one by one.  */
    556      1.1  mrg 
    557      1.1  mrg #if !IN_GCOV_TOOL
    558      1.1  mrg static
    559      1.1  mrg #endif
    560      1.1  mrg void
    561      1.1  mrg gcov_do_dump (struct gcov_info *list, int run_counted)
    562      1.1  mrg {
    563      1.1  mrg   struct gcov_info *gi_ptr;
    564      1.1  mrg   struct gcov_filename gf;
    565      1.1  mrg 
    566  1.1.1.8  mrg   /* Compute run_max of this program run.  */
    567  1.1.1.8  mrg   gcov_type run_max = 0;
    568  1.1.1.8  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    569  1.1.1.8  mrg     for (unsigned f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
    570  1.1.1.8  mrg       {
    571  1.1.1.8  mrg 	const struct gcov_ctr_info *cinfo
    572  1.1.1.8  mrg 	  = &gi_ptr->functions[f_ix]->ctrs[GCOV_COUNTER_ARCS];
    573  1.1.1.8  mrg 
    574  1.1.1.8  mrg 	for (unsigned i = 0; i < cinfo->num; i++)
    575  1.1.1.8  mrg 	  if (run_max < cinfo->values[i])
    576  1.1.1.8  mrg 	    run_max = cinfo->values[i];
    577  1.1.1.8  mrg       }
    578      1.1  mrg 
    579      1.1  mrg   allocate_filename_struct (&gf);
    580      1.1  mrg 
    581      1.1  mrg   /* Now merge each file.  */
    582      1.1  mrg   for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
    583  1.1.1.8  mrg     {
    584  1.1.1.8  mrg       dump_one_gcov (gi_ptr, &gf, run_counted, run_max);
    585  1.1.1.8  mrg       free (gf.filename);
    586  1.1.1.8  mrg     }
    587      1.1  mrg 
    588  1.1.1.8  mrg   free (gf.prefix);
    589      1.1  mrg }
    590      1.1  mrg 
    591  1.1.1.2  mrg #if IN_GCOV_TOOL
    592  1.1.1.2  mrg const char *
    593  1.1.1.2  mrg __attribute__ ((unused))
    594  1.1.1.2  mrg gcov_get_filename (struct gcov_info *list)
    595  1.1.1.2  mrg {
    596  1.1.1.2  mrg   return list->filename;
    597  1.1.1.2  mrg }
    598  1.1.1.2  mrg #endif
    599  1.1.1.2  mrg 
    600      1.1  mrg #if !IN_GCOV_TOOL
    601      1.1  mrg void
    602      1.1  mrg __gcov_dump_one (struct gcov_root *root)
    603      1.1  mrg {
    604      1.1  mrg   if (root->dumped)
    605      1.1  mrg     return;
    606      1.1  mrg 
    607      1.1  mrg   gcov_do_dump (root->list, root->run_counted);
    608      1.1  mrg 
    609      1.1  mrg   root->dumped = 1;
    610      1.1  mrg   root->run_counted = 1;
    611      1.1  mrg }
    612      1.1  mrg 
    613      1.1  mrg /* Per-dynamic-object gcov state.  */
    614      1.1  mrg struct gcov_root __gcov_root;
    615      1.1  mrg 
    616      1.1  mrg /* Exactly one of these will be live in the process image.  */
    617      1.1  mrg struct gcov_master __gcov_master =
    618      1.1  mrg   {GCOV_VERSION, 0};
    619      1.1  mrg 
    620  1.1.1.4  mrg void
    621  1.1.1.4  mrg __gcov_exit (void)
    622      1.1  mrg {
    623      1.1  mrg   __gcov_dump_one (&__gcov_root);
    624      1.1  mrg   if (__gcov_root.next)
    625      1.1  mrg     __gcov_root.next->prev = __gcov_root.prev;
    626      1.1  mrg   if (__gcov_root.prev)
    627      1.1  mrg     __gcov_root.prev->next = __gcov_root.next;
    628      1.1  mrg   else
    629      1.1  mrg     __gcov_master.root = __gcov_root.next;
    630  1.1.1.4  mrg 
    631  1.1.1.4  mrg   gcov_error_exit ();
    632      1.1  mrg }
    633      1.1  mrg 
    634      1.1  mrg /* Add a new object file onto the bb chain.  Invoked automatically
    635      1.1  mrg   when running an object file's global ctors.  */
    636      1.1  mrg 
    637      1.1  mrg void
    638      1.1  mrg __gcov_init (struct gcov_info *info)
    639      1.1  mrg {
    640      1.1  mrg   if (!info->version || !info->n_functions)
    641      1.1  mrg     return;
    642      1.1  mrg   if (gcov_version (info, info->version, 0))
    643      1.1  mrg     {
    644      1.1  mrg       if (!__gcov_root.list)
    645      1.1  mrg 	{
    646      1.1  mrg 	  /* Add to master list and at exit function.  */
    647      1.1  mrg 	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
    648      1.1  mrg 	    {
    649      1.1  mrg 	      __gcov_root.next = __gcov_master.root;
    650      1.1  mrg 	      if (__gcov_master.root)
    651      1.1  mrg 		__gcov_master.root->prev = &__gcov_root;
    652      1.1  mrg 	      __gcov_master.root = &__gcov_root;
    653      1.1  mrg 	    }
    654      1.1  mrg 	}
    655      1.1  mrg 
    656      1.1  mrg       info->next = __gcov_root.list;
    657      1.1  mrg       __gcov_root.list = info;
    658      1.1  mrg     }
    659      1.1  mrg }
    660      1.1  mrg #endif /* !IN_GCOV_TOOL */
    661      1.1  mrg #endif /* L_gcov */
    662      1.1  mrg #endif /* inhibit_libc */
    663