xref: /openbsd/gnu/gcc/gcc/libgcov.c (revision 2a970957)
1 /* Routines required for instrumenting a program.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4    2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
5 
6 This file is part of GCC.
7 
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12 
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file.  (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
21 
22 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23 WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25 for more details.
26 
27 You should have received a copy of the GNU General Public License
28 along with GCC; see the file COPYING.  If not, write to the Free
29 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 02110-1301, USA.  */
31 
32 #include "tconfig.h"
33 #include "tsystem.h"
34 #include "coretypes.h"
35 #include "tm.h"
36 
37 #if defined(inhibit_libc)
38 #define IN_LIBGCOV (-1)
39 #else
40 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
41 #include <stdio.h>
42 #define IN_LIBGCOV 1
43 #if defined(L_gcov)
44 #define GCOV_LINKAGE /* nothing */
45 #endif
46 #endif
47 #include "gcov-io.h"
48 
49 #if defined(inhibit_libc)
50 /* If libc and its header files are not available, provide dummy functions.  */
51 
52 #ifdef L_gcov
__gcov_init(struct gcov_info * p)53 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
__gcov_flush(void)54 void __gcov_flush (void) {}
55 #endif
56 
57 #ifdef L_gcov_merge_add
__gcov_merge_add(gcov_type * counters,unsigned n_counters)58 void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
59 		       unsigned n_counters __attribute__ ((unused))) {}
60 #endif
61 
62 #ifdef L_gcov_merge_single
__gcov_merge_single(gcov_type * counters,unsigned n_counters)63 void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
64 			  unsigned n_counters __attribute__ ((unused))) {}
65 #endif
66 
67 #ifdef L_gcov_merge_delta
__gcov_merge_delta(gcov_type * counters,unsigned n_counters)68 void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
69 			 unsigned n_counters __attribute__ ((unused))) {}
70 #endif
71 
72 #else
73 
74 #include <string.h>
75 #if GCOV_LOCKED
76 #include <fcntl.h>
77 #include <errno.h>
78 #include <sys/stat.h>
79 #endif
80 
81 #ifdef L_gcov
82 #include "gcov-io.c"
83 
84 /* Chain of per-object gcov structures.  */
85 static struct gcov_info *gcov_list;
86 
87 /* A program checksum allows us to distinguish program data for an
88    object file included in multiple programs.  */
89 static gcov_unsigned_t gcov_crc32;
90 
91 /* Size of the longest file name. */
92 static size_t gcov_max_filename = 0;
93 
94 #ifdef TARGET_POSIX_IO
95 /* Make sure path component of the given FILENAME exists, create
96    missing directories. FILENAME must be writable.
97    Returns zero on success, or -1 if an error occurred.  */
98 
99 static int
create_file_directory(char * filename)100 create_file_directory (char *filename)
101 {
102   char *s;
103 
104   for (s = filename + 1; *s != '\0'; s++)
105     if (IS_DIR_SEPARATOR(*s))
106       {
107         char sep = *s;
108 	*s  = '\0';
109 
110         /* Try to make directory if it doesn't already exist.  */
111         if (access (filename, F_OK) == -1
112             && mkdir (filename, 0755) == -1
113             /* The directory might have been made by another process.  */
114 	    && errno != EEXIST)
115 	  {
116             fprintf (stderr, "profiling:%s:Cannot create directory\n",
117 		     filename);
118             *s = sep;
119 	    return -1;
120 	  };
121 
122 	*s = sep;
123       };
124   return 0;
125 }
126 #endif
127 
128 /* Check if VERSION of the info block PTR matches libgcov one.
129    Return 1 on success, or zero in case of versions mismatch.
130    If FILENAME is not NULL, its value used for reporting purposes
131    instead of value from the info block.  */
132 
133 static int
gcov_version(struct gcov_info * ptr,gcov_unsigned_t version,const char * filename)134 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
135 	      const char *filename)
136 {
137   if (version != GCOV_VERSION)
138     {
139       char v[4], e[4];
140 
141       GCOV_UNSIGNED2STRING (v, version);
142       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
143 
144       fprintf (stderr,
145 	       "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
146 	       filename? filename : ptr->filename, e, v);
147       return 0;
148     }
149   return 1;
150 }
151 
152 /* Dump the coverage counts. We merge with existing counts when
153    possible, to avoid growing the .da files ad infinitum. We use this
154    program's checksum to make sure we only accumulate whole program
155    statistics to the correct summary. An object file might be embedded
156    in two separate programs, and we must keep the two program
157    summaries separate.  */
158 
159 static void
gcov_exit(void)160 gcov_exit (void)
161 {
162   struct gcov_info *gi_ptr;
163   struct gcov_summary this_program;
164   struct gcov_summary all;
165   struct gcov_ctr_summary *cs_ptr;
166   const struct gcov_ctr_info *ci_ptr;
167   unsigned t_ix;
168   gcov_unsigned_t c_num;
169   const char *gcov_prefix;
170   int gcov_prefix_strip = 0;
171   size_t prefix_length;
172   char *gi_filename, *gi_filename_up;
173 
174   memset (&all, 0, sizeof (all));
175   /* Find the totals for this execution.  */
176   memset (&this_program, 0, sizeof (this_program));
177   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
178     {
179       ci_ptr = gi_ptr->counts;
180       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
181 	{
182 	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
183 	    continue;
184 
185 	  cs_ptr = &this_program.ctrs[t_ix];
186 	  cs_ptr->num += ci_ptr->num;
187 	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
188 	    {
189       	      cs_ptr->sum_all += ci_ptr->values[c_num];
190 	      if (cs_ptr->run_max < ci_ptr->values[c_num])
191 		cs_ptr->run_max = ci_ptr->values[c_num];
192 	    }
193 	  ci_ptr++;
194 	}
195     }
196 
197   /* Get file name relocation prefix.  Non-absolute values are ignored. */
198   gcov_prefix = getenv("GCOV_PREFIX");
199   if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
200     {
201       /* Check if the level of dirs to strip off specified. */
202       char *tmp = getenv("GCOV_PREFIX_STRIP");
203       if (tmp)
204         {
205           gcov_prefix_strip = atoi (tmp);
206           /* Do not consider negative values. */
207           if (gcov_prefix_strip < 0)
208             gcov_prefix_strip = 0;
209         }
210 
211       prefix_length = strlen(gcov_prefix);
212 
213       /* Remove an unnecessary trailing '/' */
214       if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
215 	prefix_length--;
216     }
217   else
218     prefix_length = 0;
219 
220   /* Allocate and initialize the filename scratch space.  */
221   gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1);
222   if (prefix_length)
223     memcpy (gi_filename, gcov_prefix, prefix_length);
224   gi_filename_up = gi_filename + prefix_length;
225 
226   /* Now merge each file.  */
227   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
228     {
229       struct gcov_summary this_object;
230       struct gcov_summary object, program;
231       gcov_type *values[GCOV_COUNTERS];
232       const struct gcov_fn_info *fi_ptr;
233       unsigned fi_stride;
234       unsigned c_ix, f_ix, n_counts;
235       struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
236       int error = 0;
237       gcov_unsigned_t tag, length;
238       gcov_position_t summary_pos = 0;
239       gcov_position_t eof_pos = 0;
240 
241       memset (&this_object, 0, sizeof (this_object));
242       memset (&object, 0, sizeof (object));
243 
244       /* Build relocated filename, stripping off leading
245          directories from the initial filename if requested. */
246       if (gcov_prefix_strip > 0)
247         {
248           int level = 0;
249           const char *fname = gi_ptr->filename;
250           const char *s;
251 
252           /* Skip selected directory levels. */
253 	  for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
254 	    if (IS_DIR_SEPARATOR(*s))
255 	      {
256 		fname = s;
257 		level++;
258 	      };
259 
260           /* Update complete filename with stripped original. */
261           strlcpy (gi_filename_up, fname, gcov_max_filename + 1);
262         }
263       else
264         strlcpy (gi_filename_up, gi_ptr->filename, gcov_max_filename + 1);
265 
266       /* Totals for this object file.  */
267       ci_ptr = gi_ptr->counts;
268       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
269 	{
270 	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
271 	    continue;
272 
273 	  cs_ptr = &this_object.ctrs[t_ix];
274 	  cs_ptr->num += ci_ptr->num;
275 	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
276 	    {
277 	      cs_ptr->sum_all += ci_ptr->values[c_num];
278 	      if (cs_ptr->run_max < ci_ptr->values[c_num])
279 		cs_ptr->run_max = ci_ptr->values[c_num];
280 	    }
281 
282 	  ci_ptr++;
283 	}
284 
285       c_ix = 0;
286       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
287 	if ((1 << t_ix) & gi_ptr->ctr_mask)
288 	  {
289 	    values[c_ix] = gi_ptr->counts[c_ix].values;
290 	    c_ix++;
291 	  }
292 
293       /* Calculate the function_info stride. This depends on the
294 	 number of counter types being measured.  */
295       fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
296       if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
297 	{
298 	  fi_stride += __alignof__ (struct gcov_fn_info) - 1;
299 	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
300 	}
301 
302       if (!gcov_open (gi_filename))
303 	{
304 #ifdef TARGET_POSIX_IO
305 	  /* Open failed likely due to missed directory.
306 	     Create directory and retry to open file. */
307           if (create_file_directory (gi_filename))
308 	    {
309 	      fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
310 	      continue;
311 	    }
312 #endif
313 	  if (!gcov_open (gi_filename))
314 	    {
315               fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
316 	      continue;
317 	    }
318 	}
319 
320       tag = gcov_read_unsigned ();
321       if (tag)
322 	{
323 	  /* Merge data from file.  */
324 	  if (tag != GCOV_DATA_MAGIC)
325 	    {
326 	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
327 		       gi_filename);
328 	      goto read_fatal;
329 	    }
330 	  length = gcov_read_unsigned ();
331 	  if (!gcov_version (gi_ptr, length, gi_filename))
332 	    goto read_fatal;
333 
334 	  length = gcov_read_unsigned ();
335 	  if (length != gi_ptr->stamp)
336 	    /* Read from a different compilation. Overwrite the file.  */
337 	    goto rewrite;
338 
339 	  /* Merge execution counts for each function.  */
340 	  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
341 	    {
342 	      fi_ptr = (const struct gcov_fn_info *)
343 		      ((const char *) gi_ptr->functions + f_ix * fi_stride);
344 	      tag = gcov_read_unsigned ();
345 	      length = gcov_read_unsigned ();
346 
347 	      /* Check function.  */
348 	      if (tag != GCOV_TAG_FUNCTION
349 		  || length != GCOV_TAG_FUNCTION_LENGTH
350 		  || gcov_read_unsigned () != fi_ptr->ident
351 		  || gcov_read_unsigned () != fi_ptr->checksum)
352 		{
353 		read_mismatch:;
354 		  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
355 			   gi_filename,
356 			   f_ix + 1 ? "function" : "summaries");
357 		  goto read_fatal;
358 		}
359 
360 	      c_ix = 0;
361 	      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
362 		{
363 		  gcov_merge_fn merge;
364 
365 		  if (!((1 << t_ix) & gi_ptr->ctr_mask))
366 		    continue;
367 
368 		  n_counts = fi_ptr->n_ctrs[c_ix];
369 		  merge = gi_ptr->counts[c_ix].merge;
370 
371 		  tag = gcov_read_unsigned ();
372 		  length = gcov_read_unsigned ();
373 		  if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
374 		      || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
375 		    goto read_mismatch;
376 		  (*merge) (values[c_ix], n_counts);
377 		  values[c_ix] += n_counts;
378 		  c_ix++;
379 		}
380 	      if ((error = gcov_is_error ()))
381 		goto read_error;
382 	    }
383 
384 	  f_ix = ~0u;
385 	  /* Check program & object summary */
386 	  while (1)
387 	    {
388 	      int is_program;
389 
390 	      eof_pos = gcov_position ();
391 	      tag = gcov_read_unsigned ();
392 	      if (!tag)
393 		break;
394 
395 	      length = gcov_read_unsigned ();
396 	      is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
397 	      if (length != GCOV_TAG_SUMMARY_LENGTH
398 		  || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
399 		goto read_mismatch;
400 	      gcov_read_summary (is_program ? &program : &object);
401 	      if ((error = gcov_is_error ()))
402 		goto read_error;
403 	      if (is_program && program.checksum == gcov_crc32)
404 		{
405 		  summary_pos = eof_pos;
406 		  goto rewrite;
407 		}
408 	    }
409 	}
410       goto rewrite;
411 
412     read_error:;
413       fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
414 	       : "profiling:%s:Error merging\n", gi_filename);
415 
416     read_fatal:;
417       gcov_close ();
418       continue;
419 
420     rewrite:;
421       gcov_rewrite ();
422       if (!summary_pos)
423 	memset (&program, 0, sizeof (program));
424 
425       /* Merge the summaries.  */
426       f_ix = ~0u;
427       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
428 	{
429 	  cs_obj = &object.ctrs[t_ix];
430 	  cs_tobj = &this_object.ctrs[t_ix];
431 	  cs_prg = &program.ctrs[t_ix];
432 	  cs_tprg = &this_program.ctrs[t_ix];
433 	  cs_all = &all.ctrs[t_ix];
434 
435 	  if ((1 << t_ix) & gi_ptr->ctr_mask)
436 	    {
437 	      if (!cs_obj->runs++)
438 		cs_obj->num = cs_tobj->num;
439 	      else if (cs_obj->num != cs_tobj->num)
440 		goto read_mismatch;
441 	      cs_obj->sum_all += cs_tobj->sum_all;
442 	      if (cs_obj->run_max < cs_tobj->run_max)
443 		cs_obj->run_max = cs_tobj->run_max;
444 	      cs_obj->sum_max += cs_tobj->run_max;
445 
446 	      if (!cs_prg->runs++)
447 		cs_prg->num = cs_tprg->num;
448 	      else if (cs_prg->num != cs_tprg->num)
449 		goto read_mismatch;
450 	      cs_prg->sum_all += cs_tprg->sum_all;
451 	      if (cs_prg->run_max < cs_tprg->run_max)
452 		cs_prg->run_max = cs_tprg->run_max;
453 	      cs_prg->sum_max += cs_tprg->run_max;
454 	    }
455 	  else if (cs_obj->num || cs_prg->num)
456 	    goto read_mismatch;
457 
458 	  if (!cs_all->runs && cs_prg->runs)
459 	    memcpy (cs_all, cs_prg, sizeof (*cs_all));
460 	  else if (!all.checksum
461 		   && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
462 		   && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
463 	    {
464 	      fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
465 		       gi_filename, GCOV_LOCKED
466 		       ? "" : " or concurrent update without locking support");
467 	      all.checksum = ~0u;
468 	    }
469 	}
470 
471       c_ix = 0;
472       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
473 	if ((1 << t_ix) & gi_ptr->ctr_mask)
474 	  {
475 	    values[c_ix] = gi_ptr->counts[c_ix].values;
476 	    c_ix++;
477 	  }
478 
479       program.checksum = gcov_crc32;
480 
481       /* Write out the data.  */
482       gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
483       gcov_write_unsigned (gi_ptr->stamp);
484 
485       /* Write execution counts for each function.  */
486       for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
487 	{
488 	  fi_ptr = (const struct gcov_fn_info *)
489 		  ((const char *) gi_ptr->functions + f_ix * fi_stride);
490 
491 	  /* Announce function.  */
492 	  gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
493 	  gcov_write_unsigned (fi_ptr->ident);
494 	  gcov_write_unsigned (fi_ptr->checksum);
495 
496 	  c_ix = 0;
497 	  for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
498 	    {
499 	      gcov_type *c_ptr;
500 
501 	      if (!((1 << t_ix) & gi_ptr->ctr_mask))
502 		continue;
503 
504 	      n_counts = fi_ptr->n_ctrs[c_ix];
505 
506 	      gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
507 				     GCOV_TAG_COUNTER_LENGTH (n_counts));
508 	      c_ptr = values[c_ix];
509 	      while (n_counts--)
510 		gcov_write_counter (*c_ptr++);
511 
512 	      values[c_ix] = c_ptr;
513 	      c_ix++;
514 	    }
515 	}
516 
517       /* Object file summary.  */
518       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
519 
520       /* Generate whole program statistics.  */
521       if (eof_pos)
522 	gcov_seek (eof_pos);
523       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
524       if (!summary_pos)
525 	gcov_write_unsigned (0);
526       if ((error = gcov_close ()))
527 	  fprintf (stderr, error  < 0 ?
528 		   "profiling:%s:Overflow writing\n" :
529 		   "profiling:%s:Error writing\n",
530 		   gi_filename);
531     }
532 }
533 
534 /* Add a new object file onto the bb chain.  Invoked automatically
535    when running an object file's global ctors.  */
536 
537 void
__gcov_init(struct gcov_info * info)538 __gcov_init (struct gcov_info *info)
539 {
540   if (!info->version)
541     return;
542   if (gcov_version (info, info->version, 0))
543     {
544       const char *ptr = info->filename;
545       gcov_unsigned_t crc32 = gcov_crc32;
546       size_t filename_length =  strlen(info->filename);
547 
548       /* Refresh the longest file name information */
549       if (filename_length > gcov_max_filename)
550         gcov_max_filename = filename_length;
551 
552       do
553 	{
554 	  unsigned ix;
555 	  gcov_unsigned_t value = *ptr << 24;
556 
557 	  for (ix = 8; ix--; value <<= 1)
558 	    {
559 	      gcov_unsigned_t feedback;
560 
561 	      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
562 	      crc32 <<= 1;
563 	      crc32 ^= feedback;
564 	    }
565 	}
566       while (*ptr++);
567 
568       gcov_crc32 = crc32;
569 
570       if (!gcov_list)
571 	atexit (gcov_exit);
572 
573       info->next = gcov_list;
574       gcov_list = info;
575     }
576   info->version = 0;
577 }
578 
579 /* Called before fork or exec - write out profile information gathered so
580    far and reset it to zero.  This avoids duplication or loss of the
581    profile information gathered so far.  */
582 
583 void
__gcov_flush(void)584 __gcov_flush (void)
585 {
586   const struct gcov_info *gi_ptr;
587 
588   gcov_exit ();
589   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
590     {
591       unsigned t_ix;
592       const struct gcov_ctr_info *ci_ptr;
593 
594       for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
595 	if ((1 << t_ix) & gi_ptr->ctr_mask)
596 	  {
597 	    memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
598 	    ci_ptr++;
599 	  }
600     }
601 }
602 
603 #endif /* L_gcov */
604 
605 #ifdef L_gcov_merge_add
606 /* The profile merging function that just adds the counters.  It is given
607    an array COUNTERS of N_COUNTERS old counters and it reads the same number
608    of counters from the gcov file.  */
609 void
__gcov_merge_add(gcov_type * counters,unsigned n_counters)610 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
611 {
612   for (; n_counters; counters++, n_counters--)
613     *counters += gcov_read_counter ();
614 }
615 #endif /* L_gcov_merge_add */
616 
617 #ifdef L_gcov_merge_single
618 /* The profile merging function for choosing the most common value.
619    It is given an array COUNTERS of N_COUNTERS old counters and it
620    reads the same number of counters from the gcov file.  The counters
621    are split into 3-tuples where the members of the tuple have
622    meanings:
623 
624    -- the stored candidate on the most common value of the measured entity
625    -- counter
626    -- total number of evaluations of the value  */
627 void
__gcov_merge_single(gcov_type * counters,unsigned n_counters)628 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
629 {
630   unsigned i, n_measures;
631   gcov_type value, counter, all;
632 
633   gcc_assert (!(n_counters % 3));
634   n_measures = n_counters / 3;
635   for (i = 0; i < n_measures; i++, counters += 3)
636     {
637       value = gcov_read_counter ();
638       counter = gcov_read_counter ();
639       all = gcov_read_counter ();
640 
641       if (counters[0] == value)
642 	counters[1] += counter;
643       else if (counter > counters[1])
644 	{
645 	  counters[0] = value;
646 	  counters[1] = counter - counters[1];
647 	}
648       else
649 	counters[1] -= counter;
650       counters[2] += all;
651     }
652 }
653 #endif /* L_gcov_merge_single */
654 
655 #ifdef L_gcov_merge_delta
656 /* The profile merging function for choosing the most common
657    difference between two consecutive evaluations of the value.  It is
658    given an array COUNTERS of N_COUNTERS old counters and it reads the
659    same number of counters from the gcov file.  The counters are split
660    into 4-tuples where the members of the tuple have meanings:
661 
662    -- the last value of the measured entity
663    -- the stored candidate on the most common difference
664    -- counter
665    -- total number of evaluations of the value  */
666 void
__gcov_merge_delta(gcov_type * counters,unsigned n_counters)667 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
668 {
669   unsigned i, n_measures;
670   gcov_type last, value, counter, all;
671 
672   gcc_assert (!(n_counters % 4));
673   n_measures = n_counters / 4;
674   for (i = 0; i < n_measures; i++, counters += 4)
675     {
676       last = gcov_read_counter ();
677       value = gcov_read_counter ();
678       counter = gcov_read_counter ();
679       all = gcov_read_counter ();
680 
681       if (counters[1] == value)
682 	counters[2] += counter;
683       else if (counter > counters[2])
684 	{
685 	  counters[1] = value;
686 	  counters[2] = counter - counters[2];
687 	}
688       else
689 	counters[2] -= counter;
690       counters[3] += all;
691     }
692 }
693 #endif /* L_gcov_merge_delta */
694 
695 #ifdef L_gcov_interval_profiler
696 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
697    corresponding counter in COUNTERS.  If the VALUE is above or below
698    the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
699    instead.  */
700 
701 void
__gcov_interval_profiler(gcov_type * counters,gcov_type value,int start,unsigned steps)702 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
703 			  int start, unsigned steps)
704 {
705   gcov_type delta = value - start;
706   if (delta < 0)
707     counters[steps + 1]++;
708   else if (delta >= steps)
709     counters[steps]++;
710   else
711     counters[delta]++;
712 }
713 #endif
714 
715 #ifdef L_gcov_pow2_profiler
716 /* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
717    COUNTERS[0] is incremented.  */
718 
719 void
__gcov_pow2_profiler(gcov_type * counters,gcov_type value)720 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
721 {
722   if (value & (value - 1))
723     counters[0]++;
724   else
725     counters[1]++;
726 }
727 #endif
728 
729 #ifdef L_gcov_one_value_profiler
730 /* Tries to determine the most common value among its inputs.  Checks if the
731    value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
732    is incremented.  If this is not the case and COUNTERS[1] is not zero,
733    COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
734    VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
735    function is called more than 50% of the time with one value, this value
736    will be in COUNTERS[0] in the end.
737 
738    In any case, COUNTERS[2] is incremented.  */
739 
740 void
__gcov_one_value_profiler(gcov_type * counters,gcov_type value)741 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
742 {
743   if (value == counters[0])
744     counters[1]++;
745   else if (counters[1] == 0)
746     {
747       counters[1] = 1;
748       counters[0] = value;
749     }
750   else
751     counters[1]--;
752   counters[2]++;
753 }
754 #endif
755 
756 #ifdef L_gcov_fork
757 /* A wrapper for the fork function.  Flushes the accumulated profiling data, so
758    that they are not counted twice.  */
759 
760 pid_t
__gcov_fork(void)761 __gcov_fork (void)
762 {
763   __gcov_flush ();
764   return fork ();
765 }
766 #endif
767 
768 #ifdef L_gcov_execl
769 /* A wrapper for the execl function.  Flushes the accumulated profiling data, so
770    that they are not lost.  */
771 
772 int
__gcov_execl(const char * path,const char * arg,...)773 __gcov_execl (const char *path, const char *arg, ...)
774 {
775   va_list ap, aq;
776   unsigned i, length;
777   char **args;
778 
779   __gcov_flush ();
780 
781   va_start (ap, arg);
782   va_copy (aq, ap);
783 
784   length = 2;
785   while (va_arg (ap, char *))
786     length++;
787   va_end (ap);
788 
789   args = (char **) alloca (length * sizeof (void *));
790   args[0] = (char *) arg;
791   for (i = 1; i < length; i++)
792     args[i] = va_arg (aq, char *);
793   va_end (aq);
794 
795   return execv (path, args);
796 }
797 #endif
798 
799 #ifdef L_gcov_execlp
800 /* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
801    that they are not lost.  */
802 
803 int
__gcov_execlp(const char * path,const char * arg,...)804 __gcov_execlp (const char *path, const char *arg, ...)
805 {
806   va_list ap, aq;
807   unsigned i, length;
808   char **args;
809 
810   __gcov_flush ();
811 
812   va_start (ap, arg);
813   va_copy (aq, ap);
814 
815   length = 2;
816   while (va_arg (ap, char *))
817     length++;
818   va_end (ap);
819 
820   args = (char **) alloca (length * sizeof (void *));
821   args[0] = (char *) arg;
822   for (i = 1; i < length; i++)
823     args[i] = va_arg (aq, char *);
824   va_end (aq);
825 
826   return execvp (path, args);
827 }
828 #endif
829 
830 #ifdef L_gcov_execle
831 /* A wrapper for the execle function.  Flushes the accumulated profiling data, so
832    that they are not lost.  */
833 
834 int
__gcov_execle(const char * path,const char * arg,...)835 __gcov_execle (const char *path, const char *arg, ...)
836 {
837   va_list ap, aq;
838   unsigned i, length;
839   char **args;
840   char **envp;
841 
842   __gcov_flush ();
843 
844   va_start (ap, arg);
845   va_copy (aq, ap);
846 
847   length = 2;
848   while (va_arg (ap, char *))
849     length++;
850   va_end (ap);
851 
852   args = (char **) alloca (length * sizeof (void *));
853   args[0] = (char *) arg;
854   for (i = 1; i < length; i++)
855     args[i] = va_arg (aq, char *);
856   envp = va_arg (aq, char **);
857   va_end (aq);
858 
859   return execve (path, args, envp);
860 }
861 #endif
862 
863 #ifdef L_gcov_execv
864 /* A wrapper for the execv function.  Flushes the accumulated profiling data, so
865    that they are not lost.  */
866 
867 int
__gcov_execv(const char * path,char * const argv[])868 __gcov_execv (const char *path, char *const argv[])
869 {
870   __gcov_flush ();
871   return execv (path, argv);
872 }
873 #endif
874 
875 #ifdef L_gcov_execvp
876 /* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
877    that they are not lost.  */
878 
879 int
__gcov_execvp(const char * path,char * const argv[])880 __gcov_execvp (const char *path, char *const argv[])
881 {
882   __gcov_flush ();
883   return execvp (path, argv);
884 }
885 #endif
886 
887 #ifdef L_gcov_execve
888 /* A wrapper for the execve function.  Flushes the accumulated profiling data, so
889    that they are not lost.  */
890 
891 int
__gcov_execve(const char * path,char * const argv[],char * const envp[])892 __gcov_execve (const char *path, char *const argv[], char *const envp[])
893 {
894   __gcov_flush ();
895   return execve (path, argv, envp);
896 }
897 #endif
898 #endif /* inhibit_libc */
899