OSDN Git Service

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