libgcov-driver.c revision 1.4
1/* Routines required for instrumenting a program.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24<http://www.gnu.org/licenses/>.  */
25
26#include "libgcov.h"
27
28#if defined(inhibit_libc)
29/* If libc and its header files are not available, provide dummy functions.  */
30
31#if defined(L_gcov)
32void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
33#endif
34
35#else /* inhibit_libc */
36
37#include <string.h>
38#if GCOV_LOCKED
39#include <fcntl.h>
40#include <errno.h>
41#include <sys/stat.h>
42#endif
43
44#ifdef L_gcov
45
46/* A utility function for outputting errors.  */
47static int gcov_error (const char *, ...);
48
49#if !IN_GCOV_TOOL
50static void gcov_error_exit (void);
51#endif
52
53#include "gcov-io.c"
54
55struct gcov_fn_buffer
56{
57  struct gcov_fn_buffer *next;
58  unsigned fn_ix;
59  struct gcov_fn_info info;
60  /* note gcov_fn_info ends in a trailing array.  */
61};
62
63struct gcov_summary_buffer
64{
65  struct gcov_summary_buffer *next;
66  struct gcov_summary summary;
67};
68
69/* A struct that bundles all the related information about the
70   gcda filename.  */
71
72struct gcov_filename
73{
74  char *filename;  /* filename buffer */
75  size_t max_length;  /* maximum filename length */
76  int strip; /* leading chars to strip from filename */
77  size_t prefix; /* chars to prepend to filename */
78};
79
80static struct gcov_fn_buffer *
81free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
82              unsigned limit)
83{
84  struct gcov_fn_buffer *next;
85  unsigned ix, n_ctr = 0;
86
87  if (!buffer)
88    return 0;
89  next = buffer->next;
90
91  for (ix = 0; ix != limit; ix++)
92    if (gi_ptr->merge[ix])
93      free (buffer->info.ctrs[n_ctr++].values);
94  free (buffer);
95  return next;
96}
97
98static struct gcov_fn_buffer **
99buffer_fn_data (const char *filename, const struct gcov_info *gi_ptr,
100                struct gcov_fn_buffer **end_ptr, unsigned fn_ix)
101{
102  unsigned n_ctrs = 0, ix = 0;
103  struct gcov_fn_buffer *fn_buffer;
104  unsigned len;
105
106  for (ix = GCOV_COUNTERS; ix--;)
107    if (gi_ptr->merge[ix])
108      n_ctrs++;
109
110  len = sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs;
111  fn_buffer = (struct gcov_fn_buffer *) xmalloc (len);
112
113  if (!fn_buffer)
114    goto fail;
115
116  fn_buffer->next = 0;
117  fn_buffer->fn_ix = fn_ix;
118  fn_buffer->info.ident = gcov_read_unsigned ();
119  fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
120  fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
121
122  for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
123    {
124      gcov_unsigned_t length;
125      gcov_type *values;
126
127      if (!gi_ptr->merge[ix])
128        continue;
129
130      if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
131        {
132          len = 0;
133          goto fail;
134        }
135
136      length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
137      len = length * sizeof (gcov_type);
138      values = (gcov_type *) xmalloc (len);
139      if (!values)
140        goto fail;
141
142      fn_buffer->info.ctrs[n_ctrs].num = length;
143      fn_buffer->info.ctrs[n_ctrs].values = values;
144
145      while (length--)
146        *values++ = gcov_read_counter ();
147      n_ctrs++;
148    }
149
150  *end_ptr = fn_buffer;
151  return &fn_buffer->next;
152
153fail:
154  gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix,
155              len ? "cannot allocate" : "counter mismatch", len ? len : ix);
156
157  return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
158}
159
160/* Add an unsigned value to the current crc */
161
162static gcov_unsigned_t
163crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value)
164{
165  unsigned ix;
166
167  for (ix = 32; ix--; value <<= 1)
168    {
169      unsigned feedback;
170
171      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
172      crc32 <<= 1;
173      crc32 ^= feedback;
174    }
175
176  return crc32;
177}
178
179/* Check if VERSION of the info block PTR matches libgcov one.
180   Return 1 on success, or zero in case of versions mismatch.
181   If FILENAME is not NULL, its value used for reporting purposes
182   instead of value from the info block.  */
183
184static int
185gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
186              const char *filename)
187{
188  if (version != GCOV_VERSION)
189    {
190      char v[4], e[4];
191
192      GCOV_UNSIGNED2STRING (v, version);
193      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
194
195      gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
196                  filename? filename : ptr->filename, e, v);
197      return 0;
198    }
199  return 1;
200}
201
202/* Insert counter VALUE into HISTOGRAM.  */
203
204static void
205gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value)
206{
207  unsigned i;
208
209  i = gcov_histo_index(value);
210  histogram[i].num_counters++;
211  histogram[i].cum_value += value;
212  if (value < histogram[i].min_value)
213    histogram[i].min_value = value;
214}
215
216/* Computes a histogram of the arc counters to place in the summary SUM.  */
217
218static void
219gcov_compute_histogram (struct gcov_info *list, struct gcov_summary *sum)
220{
221  struct gcov_info *gi_ptr;
222  const struct gcov_fn_info *gfi_ptr;
223  const struct gcov_ctr_info *ci_ptr;
224  struct gcov_ctr_summary *cs_ptr;
225  unsigned t_ix, f_ix, ctr_info_ix, ix;
226  int h_ix;
227
228  /* This currently only applies to arc counters.  */
229  t_ix = GCOV_COUNTER_ARCS;
230
231  /* First check if there are any counts recorded for this counter.  */
232  cs_ptr = &(sum->ctrs[t_ix]);
233  if (!cs_ptr->num)
234    return;
235
236  for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++)
237    {
238      cs_ptr->histogram[h_ix].num_counters = 0;
239      cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max;
240      cs_ptr->histogram[h_ix].cum_value = 0;
241    }
242
243  /* Walk through all the per-object structures and record each of
244     the count values in histogram.  */
245  for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
246    {
247      if (!gi_ptr->merge[t_ix])
248        continue;
249
250      /* Find the appropriate index into the gcov_ctr_info array
251         for the counter we are currently working on based on the
252         existence of the merge function pointer for this object.  */
253      for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++)
254        {
255          if (gi_ptr->merge[ix])
256            ctr_info_ix++;
257        }
258      for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
259        {
260          gfi_ptr = gi_ptr->functions[f_ix];
261
262          if (!gfi_ptr || gfi_ptr->key != gi_ptr)
263            continue;
264
265          ci_ptr = &gfi_ptr->ctrs[ctr_info_ix];
266          for (ix = 0; ix < ci_ptr->num; ix++)
267            gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]);
268        }
269    }
270}
271
272/* buffer for the fn_data from another program.  */
273static struct gcov_fn_buffer *fn_buffer;
274/* buffer for summary from other programs to be written out. */
275static struct gcov_summary_buffer *sum_buffer;
276
277/* This function computes the program level summary and the histo-gram.
278   It computes and returns CRC32 and stored summary in THIS_PRG.
279   Also determines the longest filename length of the info files.  */
280
281#if !IN_GCOV_TOOL
282static
283#endif
284gcov_unsigned_t
285compute_summary (struct gcov_info *list, struct gcov_summary *this_prg,
286		 size_t *max_length)
287{
288  struct gcov_info *gi_ptr;
289  const struct gcov_fn_info *gfi_ptr;
290  struct gcov_ctr_summary *cs_ptr;
291  const struct gcov_ctr_info *ci_ptr;
292  int f_ix;
293  unsigned t_ix;
294  gcov_unsigned_t c_num;
295  gcov_unsigned_t crc32 = 0;
296
297  /* Find the totals for this execution.  */
298  memset (this_prg, 0, sizeof (*this_prg));
299  *max_length = 0;
300  for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
301    {
302      size_t len = strlen (gi_ptr->filename);
303      if (len > *max_length)
304	*max_length = len;
305
306      crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
307      crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
308
309      for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
310        {
311          gfi_ptr = gi_ptr->functions[f_ix];
312
313          if (gfi_ptr && gfi_ptr->key != gi_ptr)
314            gfi_ptr = 0;
315
316          crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0);
317          crc32 = crc32_unsigned (crc32,
318                                  gfi_ptr ? gfi_ptr->lineno_checksum : 0);
319          if (!gfi_ptr)
320            continue;
321
322          ci_ptr = gfi_ptr->ctrs;
323          for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
324            {
325              if (!gi_ptr->merge[t_ix])
326                continue;
327
328              cs_ptr = &(this_prg->ctrs[t_ix]);
329              cs_ptr->num += ci_ptr->num;
330              crc32 = crc32_unsigned (crc32, ci_ptr->num);
331
332              for (c_num = 0; c_num < ci_ptr->num; c_num++)
333                {
334                  cs_ptr->sum_all += ci_ptr->values[c_num];
335                  if (cs_ptr->run_max < ci_ptr->values[c_num])
336                    cs_ptr->run_max = ci_ptr->values[c_num];
337                }
338              ci_ptr++;
339            }
340        }
341    }
342  gcov_compute_histogram (list, this_prg);
343  return crc32;
344}
345
346/* Including system dependent components. */
347#include "libgcov-driver-system.c"
348
349/* This function merges counters in GI_PTR to an existing gcda file.
350   Return 0 on success.
351   Return -1 on error. In this case, caller will goto read_fatal.  */
352
353static int
354merge_one_data (const char *filename,
355		struct gcov_info *gi_ptr,
356		struct gcov_summary *prg_p,
357		struct gcov_summary *this_prg,
358		gcov_position_t *summary_pos_p,
359		gcov_position_t *eof_pos_p,
360		gcov_unsigned_t crc32)
361{
362  gcov_unsigned_t tag, length;
363  unsigned t_ix;
364  int f_ix;
365  int error = 0;
366  struct gcov_fn_buffer **fn_tail = &fn_buffer;
367  struct gcov_summary_buffer **sum_tail = &sum_buffer;
368
369  length = gcov_read_unsigned ();
370  if (!gcov_version (gi_ptr, length, filename))
371    return -1;
372
373  length = gcov_read_unsigned ();
374  if (length != gi_ptr->stamp)
375    /* Read from a different compilation. Overwrite the file.  */
376    return 0;
377
378  /* Look for program summary.  */
379  for (f_ix = 0;;)
380    {
381      struct gcov_summary tmp;
382
383      *eof_pos_p = gcov_position ();
384      tag = gcov_read_unsigned ();
385      if (tag != GCOV_TAG_PROGRAM_SUMMARY)
386        break;
387
388      f_ix--;
389      length = gcov_read_unsigned ();
390      gcov_read_summary (&tmp);
391      if ((error = gcov_is_error ()))
392        goto read_error;
393      if (*summary_pos_p)
394        {
395          /* Save all summaries after the one that will be
396             merged into below. These will need to be rewritten
397             as histogram merging may change the number of non-zero
398             histogram entries that will be emitted, and thus the
399             size of the merged summary.  */
400          (*sum_tail) = (struct gcov_summary_buffer *)
401              xmalloc (sizeof(struct gcov_summary_buffer));
402          (*sum_tail)->summary = tmp;
403          (*sum_tail)->next = 0;
404          sum_tail = &((*sum_tail)->next);
405          goto next_summary;
406        }
407      if (tmp.checksum != crc32)
408        goto next_summary;
409
410      for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
411        if (tmp.ctrs[t_ix].num != this_prg->ctrs[t_ix].num)
412          goto next_summary;
413      *prg_p = tmp;
414      *summary_pos_p = *eof_pos_p;
415
416    next_summary:;
417    }
418
419  /* Merge execution counts for each function.  */
420  for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions;
421       f_ix++, tag = gcov_read_unsigned ())
422    {
423      const struct gcov_ctr_info *ci_ptr;
424      const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
425
426      if (tag != GCOV_TAG_FUNCTION)
427        goto read_mismatch;
428
429      length = gcov_read_unsigned ();
430      if (!length)
431        /* This function did not appear in the other program.
432           We have nothing to merge.  */
433        continue;
434
435      if (length != GCOV_TAG_FUNCTION_LENGTH)
436        goto read_mismatch;
437
438      if (!gfi_ptr || gfi_ptr->key != gi_ptr)
439        {
440          /* This function appears in the other program.  We
441             need to buffer the information in order to write
442             it back out -- we'll be inserting data before
443             this point, so cannot simply keep the data in the
444             file.  */
445          fn_tail = buffer_fn_data (filename, gi_ptr, fn_tail, f_ix);
446          if (!fn_tail)
447            goto read_mismatch;
448          continue;
449        }
450
451      length = gcov_read_unsigned ();
452      if (length != gfi_ptr->ident)
453        goto read_mismatch;
454
455      length = gcov_read_unsigned ();
456      if (length != gfi_ptr->lineno_checksum)
457        goto read_mismatch;
458
459      length = gcov_read_unsigned ();
460      if (length != gfi_ptr->cfg_checksum)
461        goto read_mismatch;
462
463      ci_ptr = gfi_ptr->ctrs;
464      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
465        {
466          gcov_merge_fn merge = gi_ptr->merge[t_ix];
467
468          if (!merge)
469            continue;
470
471          tag = gcov_read_unsigned ();
472          length = gcov_read_unsigned ();
473          if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
474              || length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
475            goto read_mismatch;
476          (*merge) (ci_ptr->values, ci_ptr->num);
477          ci_ptr++;
478        }
479      if ((error = gcov_is_error ()))
480        goto read_error;
481    }
482
483  if (tag)
484    {
485    read_mismatch:;
486      gcov_error ("profiling:%s:Merge mismatch for %s %u\n",
487                  filename, f_ix >= 0 ? "function" : "summary",
488                  f_ix < 0 ? -1 - f_ix : f_ix);
489      return -1;
490    }
491  return 0;
492
493read_error:
494  gcov_error ("profiling:%s:%s merging\n", filename,
495              error < 0 ? "Overflow": "Error");
496  return -1;
497}
498
499/* Write counters in GI_PTR and the summary in PRG to a gcda file. In
500   the case of appending to an existing file, SUMMARY_POS will be non-zero.
501   We will write the file starting from SUMMAY_POS.  */
502
503static void
504write_one_data (const struct gcov_info *gi_ptr,
505		const struct gcov_summary *prg_p,
506		const gcov_position_t eof_pos,
507		const gcov_position_t summary_pos)
508{
509  unsigned f_ix;
510  struct gcov_summary_buffer *next_sum_buffer;
511
512  /* Write out the data.  */
513  if (!eof_pos)
514    {
515      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
516      gcov_write_unsigned (gi_ptr->stamp);
517    }
518
519  if (summary_pos)
520    gcov_seek (summary_pos);
521
522  /* Generate whole program statistics.  */
523  gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p);
524
525  /* Rewrite all the summaries that were after the summary we merged
526     into. This is necessary as the merged summary may have a different
527     size due to the number of non-zero histogram entries changing after
528     merging.  */
529
530  while (sum_buffer)
531    {
532      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
533      next_sum_buffer = sum_buffer->next;
534      free (sum_buffer);
535      sum_buffer = next_sum_buffer;
536    }
537
538  /* Write execution counts for each function.  */
539  for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
540    {
541      unsigned buffered = 0;
542      const struct gcov_fn_info *gfi_ptr;
543      const struct gcov_ctr_info *ci_ptr;
544      gcov_unsigned_t length;
545      unsigned t_ix;
546
547      if (fn_buffer && fn_buffer->fn_ix == f_ix)
548        {
549          /* Buffered data from another program.  */
550          buffered = 1;
551          gfi_ptr = &fn_buffer->info;
552          length = GCOV_TAG_FUNCTION_LENGTH;
553        }
554      else
555        {
556          gfi_ptr = gi_ptr->functions[f_ix];
557          if (gfi_ptr && gfi_ptr->key == gi_ptr)
558            length = GCOV_TAG_FUNCTION_LENGTH;
559          else
560                length = 0;
561        }
562
563      gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
564      if (!length)
565        continue;
566
567      gcov_write_unsigned (gfi_ptr->ident);
568      gcov_write_unsigned (gfi_ptr->lineno_checksum);
569      gcov_write_unsigned (gfi_ptr->cfg_checksum);
570
571      ci_ptr = gfi_ptr->ctrs;
572      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
573        {
574          gcov_unsigned_t n_counts;
575          gcov_type *c_ptr;
576
577          if (!gi_ptr->merge[t_ix])
578            continue;
579
580          n_counts = ci_ptr->num;
581          gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
582                                 GCOV_TAG_COUNTER_LENGTH (n_counts));
583          c_ptr = ci_ptr->values;
584          while (n_counts--)
585            gcov_write_counter (*c_ptr++);
586          ci_ptr++;
587        }
588      if (buffered)
589        fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
590    }
591
592  gcov_write_unsigned (0);
593}
594
595/* Helper function for merging summary.
596   Return -1 on error. Return 0 on success.  */
597
598static int
599merge_summary (const char *filename, int run_counted,
600	       const struct gcov_info *gi_ptr, struct gcov_summary *prg,
601	       struct gcov_summary *this_prg, gcov_unsigned_t crc32,
602	       struct gcov_summary *all_prg __attribute__ ((unused)))
603{
604  struct gcov_ctr_summary *cs_prg, *cs_tprg;
605  unsigned t_ix;
606#if !GCOV_LOCKED
607  /* summary for all instances of program.  */
608  struct gcov_ctr_summary *cs_all;
609#endif
610
611  /* Merge the summaries.  */
612  for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
613    {
614      cs_prg = &(prg->ctrs[t_ix]);
615      cs_tprg = &(this_prg->ctrs[t_ix]);
616
617      if (gi_ptr->merge[t_ix])
618        {
619	  int first = !cs_prg->runs;
620
621	  if (!run_counted)
622	    cs_prg->runs++;
623          if (first)
624            cs_prg->num = cs_tprg->num;
625          cs_prg->sum_all += cs_tprg->sum_all;
626          if (cs_prg->run_max < cs_tprg->run_max)
627            cs_prg->run_max = cs_tprg->run_max;
628          cs_prg->sum_max += cs_tprg->run_max;
629          if (first)
630            memcpy (cs_prg->histogram, cs_tprg->histogram,
631                   sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
632          else
633            gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram);
634        }
635      else if (cs_prg->runs)
636        {
637          gcov_error ("profiling:%s:Merge mismatch for summary.\n",
638                      filename);
639          return -1;
640        }
641#if !GCOV_LOCKED
642      cs_all = &all_prg->ctrs[t_ix];
643      if (!cs_all->runs && cs_prg->runs)
644        {
645          cs_all->num = cs_prg->num;
646          cs_all->runs = cs_prg->runs;
647          cs_all->sum_all = cs_prg->sum_all;
648          cs_all->run_max = cs_prg->run_max;
649          cs_all->sum_max = cs_prg->sum_max;
650        }
651      else if (!all_prg->checksum
652               /* Don't compare the histograms, which may have slight
653                  variations depending on the order they were updated
654                  due to the truncating integer divides used in the
655                  merge.  */
656               && (cs_all->num != cs_prg->num
657                   || cs_all->runs != cs_prg->runs
658                   || cs_all->sum_all != cs_prg->sum_all
659                   || cs_all->run_max != cs_prg->run_max
660                   || cs_all->sum_max != cs_prg->sum_max))
661             {
662               gcov_error ("profiling:%s:Data file mismatch - some "
663                           "data files may have been concurrently "
664                           "updated without locking support\n", filename);
665               all_prg->checksum = ~0u;
666             }
667#endif
668    }
669
670  prg->checksum = crc32;
671
672  return 0;
673}
674
675
676/* Sort N entries in VALUE_ARRAY in descending order.
677   Each entry in VALUE_ARRAY has two values. The sorting
678   is based on the second value.  */
679
680GCOV_LINKAGE  void
681gcov_sort_n_vals (gcov_type *value_array, int n)
682{
683  int j, k;
684
685  for (j = 2; j < n; j += 2)
686    {
687      gcov_type cur_ent[2];
688
689      cur_ent[0] = value_array[j];
690      cur_ent[1] = value_array[j + 1];
691      k = j - 2;
692      while (k >= 0 && value_array[k + 1] < cur_ent[1])
693        {
694          value_array[k + 2] = value_array[k];
695          value_array[k + 3] = value_array[k+1];
696          k -= 2;
697        }
698      value_array[k + 2] = cur_ent[0];
699      value_array[k + 3] = cur_ent[1];
700    }
701}
702
703/* Sort the profile counters for all indirect call sites. Counters
704   for each call site are allocated in array COUNTERS.  */
705
706static void
707gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
708{
709  int i;
710  gcov_type *values;
711  int n = counters->num;
712
713  gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
714  values = counters->values;
715
716  for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
717    {
718      gcov_type *value_array = &values[i + 1];
719      gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
720    }
721}
722
723/* Sort topn indirect_call profile counters in GI_PTR.  */
724
725static void
726gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
727{
728  unsigned int i;
729  int f_ix;
730  const struct gcov_fn_info *gfi_ptr;
731  const struct gcov_ctr_info *ci_ptr;
732
733  if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
734    return;
735
736  for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
737    {
738      gfi_ptr = gi_ptr->functions[f_ix];
739      ci_ptr = gfi_ptr->ctrs;
740      for (i = 0; i < GCOV_COUNTERS; i++)
741        {
742          if (!gi_ptr->merge[i])
743            continue;
744          if (i == GCOV_COUNTER_ICALL_TOPNV)
745            {
746              gcov_sort_icall_topn_counter (ci_ptr);
747              break;
748            }
749          ci_ptr++;
750        }
751    }
752}
753
754/* Dump the coverage counts for one gcov_info object. We merge with existing
755   counts when possible, to avoid growing the .da files ad infinitum. We use
756   this program's checksum to make sure we only accumulate whole program
757   statistics to the correct summary. An object file might be embedded
758   in two separate programs, and we must keep the two program
759   summaries separate.  */
760
761static void
762dump_one_gcov (struct gcov_info *gi_ptr, struct gcov_filename *gf,
763	       unsigned run_counted,
764	       gcov_unsigned_t crc32, struct gcov_summary *all_prg,
765	       struct gcov_summary *this_prg)
766{
767  struct gcov_summary prg; /* summary for this object over all program.  */
768  int error;
769  gcov_unsigned_t tag;
770  gcov_position_t summary_pos = 0;
771  gcov_position_t eof_pos = 0;
772
773  fn_buffer = 0;
774  sum_buffer = 0;
775
776  gcov_sort_topn_counter_arrays (gi_ptr);
777
778  error = gcov_exit_open_gcda_file (gi_ptr, gf);
779  if (error == -1)
780    return;
781
782  tag = gcov_read_unsigned ();
783  if (tag)
784    {
785      /* Merge data from file.  */
786      if (tag != GCOV_DATA_MAGIC)
787        {
788          gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename);
789          goto read_fatal;
790        }
791      error = merge_one_data (gf->filename, gi_ptr, &prg, this_prg,
792			      &summary_pos, &eof_pos, crc32);
793      if (error == -1)
794        goto read_fatal;
795    }
796
797  gcov_rewrite ();
798
799  if (!summary_pos)
800    {
801      memset (&prg, 0, sizeof (prg));
802      summary_pos = eof_pos;
803    }
804
805  error = merge_summary (gf->filename, run_counted, gi_ptr, &prg, this_prg,
806			 crc32, all_prg);
807  if (error == -1)
808    goto read_fatal;
809
810  write_one_data (gi_ptr, &prg, eof_pos, summary_pos);
811  /* fall through */
812
813read_fatal:;
814  while (fn_buffer)
815    fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
816
817  if ((error = gcov_close ()))
818    gcov_error (error  < 0 ?
819                "profiling:%s:Overflow writing\n" :
820                "profiling:%s:Error writing\n",
821                gf->filename);
822}
823
824
825/* Dump all the coverage counts for the program. It first computes program
826   summary and then traverses gcov_list list and dumps the gcov_info
827   objects one by one.  */
828
829#if !IN_GCOV_TOOL
830static
831#endif
832void
833gcov_do_dump (struct gcov_info *list, int run_counted)
834{
835  struct gcov_info *gi_ptr;
836  struct gcov_filename gf;
837  gcov_unsigned_t crc32;
838  struct gcov_summary all_prg;
839  struct gcov_summary this_prg;
840
841  crc32 = compute_summary (list, &this_prg, &gf.max_length);
842
843  allocate_filename_struct (&gf);
844#if !GCOV_LOCKED
845  memset (&all_prg, 0, sizeof (all_prg));
846#endif
847
848  /* Now merge each file.  */
849  for (gi_ptr = list; gi_ptr; gi_ptr = gi_ptr->next)
850    dump_one_gcov (gi_ptr, &gf, run_counted, crc32, &all_prg, &this_prg);
851
852  free (gf.filename);
853}
854
855#if IN_GCOV_TOOL
856const char *
857__attribute__ ((unused))
858gcov_get_filename (struct gcov_info *list)
859{
860  return list->filename;
861}
862#endif
863
864#if !IN_GCOV_TOOL
865void
866__gcov_dump_one (struct gcov_root *root)
867{
868  if (root->dumped)
869    return;
870
871  gcov_do_dump (root->list, root->run_counted);
872
873  root->dumped = 1;
874  root->run_counted = 1;
875}
876
877/* Per-dynamic-object gcov state.  */
878struct gcov_root __gcov_root;
879
880/* Exactly one of these will be live in the process image.  */
881struct gcov_master __gcov_master =
882  {GCOV_VERSION, 0};
883
884void
885__gcov_exit (void)
886{
887  __gcov_dump_one (&__gcov_root);
888  if (__gcov_root.next)
889    __gcov_root.next->prev = __gcov_root.prev;
890  if (__gcov_root.prev)
891    __gcov_root.prev->next = __gcov_root.next;
892  else
893    __gcov_master.root = __gcov_root.next;
894
895  gcov_error_exit ();
896}
897
898/* Add a new object file onto the bb chain.  Invoked automatically
899  when running an object file's global ctors.  */
900
901void
902__gcov_init (struct gcov_info *info)
903{
904  if (!info->version || !info->n_functions)
905    return;
906  if (gcov_version (info, info->version, 0))
907    {
908      if (!__gcov_root.list)
909	{
910	  /* Add to master list and at exit function.  */
911	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
912	    {
913	      __gcov_root.next = __gcov_master.root;
914	      if (__gcov_master.root)
915		__gcov_master.root->prev = &__gcov_root;
916	      __gcov_master.root = &__gcov_root;
917	    }
918	}
919
920      info->next = __gcov_root.list;
921      __gcov_root.list = info;
922    }
923}
924#endif /* !IN_GCOV_TOOL */
925#endif /* L_gcov */
926#endif /* inhibit_libc */
927