OSDN Git Service

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