OSDN Git Service

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