OSDN Git Service

2008-11-03 Sebastian Pop <sebastian.pop@amd.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, 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
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 #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
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
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
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           strcpy (gi_filename_up, fname);
262         }
263       else
264         strcpy (gi_filename_up, gi_ptr->filename);
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
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
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
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_ior
618 /* The profile merging function that just adds the counters.  It is given
619    an array COUNTERS of N_COUNTERS old counters and it reads the same number
620    of counters from the gcov file.  */
621 void
622 __gcov_merge_ior (gcov_type *counters, unsigned n_counters)
623 {
624   for (; n_counters; counters++, n_counters--)
625     *counters |= gcov_read_counter ();
626 }
627 #endif
628
629 #ifdef L_gcov_merge_single
630 /* The profile merging function for choosing the most common value.
631    It is given an array COUNTERS of N_COUNTERS old counters and it
632    reads the same number of counters from the gcov file.  The counters
633    are split into 3-tuples where the members of the tuple have
634    meanings:
635    
636    -- the stored candidate on the most common value of the measured entity
637    -- counter
638    -- total number of evaluations of the value  */
639 void
640 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
641 {
642   unsigned i, n_measures;
643   gcov_type value, counter, all;
644
645   gcc_assert (!(n_counters % 3));
646   n_measures = n_counters / 3;
647   for (i = 0; i < n_measures; i++, counters += 3)
648     {
649       value = gcov_read_counter ();
650       counter = gcov_read_counter ();
651       all = gcov_read_counter ();
652
653       if (counters[0] == value)
654         counters[1] += counter;
655       else if (counter > counters[1])
656         {
657           counters[0] = value;
658           counters[1] = counter - counters[1];
659         }
660       else
661         counters[1] -= counter;
662       counters[2] += all;
663     }
664 }
665 #endif /* L_gcov_merge_single */
666
667 #ifdef L_gcov_merge_delta
668 /* The profile merging function for choosing the most common
669    difference between two consecutive evaluations of the value.  It is
670    given an array COUNTERS of N_COUNTERS old counters and it reads the
671    same number of counters from the gcov file.  The counters are split
672    into 4-tuples where the members of the tuple have meanings:
673    
674    -- the last value of the measured entity
675    -- the stored candidate on the most common difference
676    -- counter
677    -- total number of evaluations of the value  */
678 void
679 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
680 {
681   unsigned i, n_measures;
682   gcov_type last, value, counter, all;
683
684   gcc_assert (!(n_counters % 4));
685   n_measures = n_counters / 4;
686   for (i = 0; i < n_measures; i++, counters += 4)
687     {
688       last = gcov_read_counter ();
689       value = gcov_read_counter ();
690       counter = gcov_read_counter ();
691       all = gcov_read_counter ();
692
693       if (counters[1] == value)
694         counters[2] += counter;
695       else if (counter > counters[2])
696         {
697           counters[1] = value;
698           counters[2] = counter - counters[2];
699         }
700       else
701         counters[2] -= counter;
702       counters[3] += all;
703     }
704 }
705 #endif /* L_gcov_merge_delta */
706
707 #ifdef L_gcov_interval_profiler
708 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
709    corresponding counter in COUNTERS.  If the VALUE is above or below
710    the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
711    instead.  */
712
713 void
714 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
715                           int start, unsigned steps)
716 {
717   gcov_type delta = value - start;
718   if (delta < 0)
719     counters[steps + 1]++;
720   else if (delta >= steps)
721     counters[steps]++;
722   else
723     counters[delta]++;
724 }
725 #endif
726
727 #ifdef L_gcov_pow2_profiler
728 /* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
729    COUNTERS[0] is incremented.  */
730
731 void
732 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
733 {
734   if (value & (value - 1))
735     counters[0]++;
736   else
737     counters[1]++;
738 }
739 #endif
740
741 /* Tries to determine the most common value among its inputs.  Checks if the
742    value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
743    is incremented.  If this is not the case and COUNTERS[1] is not zero,
744    COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
745    VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
746    function is called more than 50% of the time with one value, this value
747    will be in COUNTERS[0] in the end.
748
749    In any case, COUNTERS[2] is incremented.  */
750
751 static inline void
752 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
753 {
754   if (value == counters[0])
755     counters[1]++;
756   else if (counters[1] == 0)
757     {
758       counters[1] = 1;
759       counters[0] = value;
760     }
761   else
762     counters[1]--;
763   counters[2]++;
764 }
765
766 #ifdef L_gcov_one_value_profiler
767 void
768 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
769 {
770   __gcov_one_value_profiler_body (counters, value);
771 }
772 #endif
773
774 #ifdef L_gcov_indirect_call_profiler
775 /* Tries to determine the most common value among its inputs. */
776 void
777 __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value, 
778                                void* cur_func, void* callee_func)
779 {
780   /* If the C++ virtual tables contain function descriptors then one
781      function may have multiple descriptors and we need to dereference
782      the descriptors to see if they point to the same function.  */
783   if (cur_func == callee_func
784       || (TARGET_VTABLE_USES_DESCRIPTORS && callee_func
785           && *(void **) cur_func == *(void **) callee_func))
786     __gcov_one_value_profiler_body (counter, value);
787 }
788 #endif
789
790
791 #ifdef L_gcov_average_profiler
792 /* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
793    to saturate up.  */
794
795 void
796 __gcov_average_profiler (gcov_type *counters, gcov_type value)
797 {
798   counters[0] += value;
799   counters[1] ++;
800 }
801 #endif
802
803 #ifdef L_gcov_ior_profiler
804 /* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
805    to saturate up.  */
806
807 void
808 __gcov_ior_profiler (gcov_type *counters, gcov_type value)
809 {
810   *counters |= value;
811 }
812 #endif
813
814 #ifdef L_gcov_fork
815 /* A wrapper for the fork function.  Flushes the accumulated profiling data, so
816    that they are not counted twice.  */
817
818 pid_t
819 __gcov_fork (void)
820 {
821   __gcov_flush ();
822   return fork ();
823 }
824 #endif
825
826 #ifdef L_gcov_execl
827 /* A wrapper for the execl function.  Flushes the accumulated profiling data, so
828    that they are not lost.  */
829
830 int
831 __gcov_execl (const char *path, const char *arg, ...)
832 {
833   va_list ap, aq;
834   unsigned i, length;
835   char **args;
836
837   __gcov_flush ();
838
839   va_start (ap, arg);
840   va_copy (aq, ap);
841
842   length = 2;
843   while (va_arg (ap, char *))
844     length++;
845   va_end (ap);
846
847   args = (char **) alloca (length * sizeof (void *));
848   args[0] = (char *) arg;
849   for (i = 1; i < length; i++)
850     args[i] = va_arg (aq, char *);
851   va_end (aq);
852
853   return execv (path, args);
854 }
855 #endif
856
857 #ifdef L_gcov_execlp
858 /* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
859    that they are not lost.  */
860
861 int
862 __gcov_execlp (const char *path, const char *arg, ...)
863 {
864   va_list ap, aq;
865   unsigned i, length;
866   char **args;
867
868   __gcov_flush ();
869
870   va_start (ap, arg);
871   va_copy (aq, ap);
872
873   length = 2;
874   while (va_arg (ap, char *))
875     length++;
876   va_end (ap);
877
878   args = (char **) alloca (length * sizeof (void *));
879   args[0] = (char *) arg;
880   for (i = 1; i < length; i++)
881     args[i] = va_arg (aq, char *);
882   va_end (aq);
883
884   return execvp (path, args);
885 }
886 #endif
887
888 #ifdef L_gcov_execle
889 /* A wrapper for the execle function.  Flushes the accumulated profiling data, so
890    that they are not lost.  */
891
892 int
893 __gcov_execle (const char *path, const char *arg, ...)
894 {
895   va_list ap, aq;
896   unsigned i, length;
897   char **args;
898   char **envp;
899
900   __gcov_flush ();
901
902   va_start (ap, arg);
903   va_copy (aq, ap);
904
905   length = 2;
906   while (va_arg (ap, char *))
907     length++;
908   va_end (ap);
909
910   args = (char **) alloca (length * sizeof (void *));
911   args[0] = (char *) arg;
912   for (i = 1; i < length; i++)
913     args[i] = va_arg (aq, char *);
914   envp = va_arg (aq, char **);
915   va_end (aq);
916
917   return execve (path, args, envp);
918 }
919 #endif
920
921 #ifdef L_gcov_execv
922 /* A wrapper for the execv function.  Flushes the accumulated profiling data, so
923    that they are not lost.  */
924
925 int
926 __gcov_execv (const char *path, char *const argv[])
927 {
928   __gcov_flush ();
929   return execv (path, argv);
930 }
931 #endif
932
933 #ifdef L_gcov_execvp
934 /* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
935    that they are not lost.  */
936
937 int
938 __gcov_execvp (const char *path, char *const argv[])
939 {
940   __gcov_flush ();
941   return execvp (path, argv);
942 }
943 #endif
944
945 #ifdef L_gcov_execve
946 /* A wrapper for the execve function.  Flushes the accumulated profiling data, so
947    that they are not lost.  */
948
949 int
950 __gcov_execve (const char *path, char *const argv[], char *const envp[])
951 {
952   __gcov_flush ();
953   return execve (path, argv, envp);
954 }
955 #endif
956 #endif /* inhibit_libc */