1  /* Routines required for instrumenting a program.  */
       2  /* Compile this one with gcc.  */
       3  /* Copyright (C) 1989-2023 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 */