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