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