OSDN Git Service

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