OSDN Git Service

2005-03-04 Andrew Haley <aph@redhat.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  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   GCOV_CHECK (!(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   GCOV_CHECK (!(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_fork
585 /* A wrapper for the fork function.  Flushes the accumulated profiling data, so
586    that they are not counted twice.  */
587
588 pid_t
589 __gcov_fork (void)
590 {
591   __gcov_flush ();
592   return fork ();
593 }
594 #endif
595
596 #ifdef L_gcov_execl
597 /* A wrapper for the execl function.  Flushes the accumulated profiling data, so
598    that they are not lost.  */
599
600 int
601 __gcov_execl (const char *path, const char *arg, ...)
602 {
603   va_list ap, aq;
604   unsigned i, length;
605   char **args;
606
607   __gcov_flush ();
608
609   va_start (ap, arg);
610   va_copy (aq, ap);
611
612   length = 2;
613   while (va_arg (ap, char *))
614     length++;
615   va_end (ap);
616
617   args = alloca (length * sizeof (void *));
618   args[0] = (char *) arg;
619   for (i = 1; i < length; i++)
620     args[i] = va_arg (aq, char *);
621   va_end (aq);
622
623   return execv (path, args);
624 }
625 #endif
626
627 #ifdef L_gcov_execlp
628 /* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
629    that they are not lost.  */
630
631 int
632 __gcov_execlp (const char *path, const char *arg, ...)
633 {
634   va_list ap, aq;
635   unsigned i, length;
636   char **args;
637
638   __gcov_flush ();
639
640   va_start (ap, arg);
641   va_copy (aq, ap);
642
643   length = 2;
644   while (va_arg (ap, char *))
645     length++;
646   va_end (ap);
647
648   args = alloca (length * sizeof (void *));
649   args[0] = (char *) arg;
650   for (i = 1; i < length; i++)
651     args[i] = va_arg (aq, char *);
652   va_end (aq);
653
654   return execvp (path, args);
655 }
656 #endif
657
658 #ifdef L_gcov_execle
659 /* A wrapper for the execle function.  Flushes the accumulated profiling data, so
660    that they are not lost.  */
661
662 int
663 __gcov_execle (const char *path, const char *arg, ...)
664 {
665   va_list ap, aq;
666   unsigned i, length;
667   char **args;
668   char **envp;
669
670   __gcov_flush ();
671
672   va_start (ap, arg);
673   va_copy (aq, ap);
674
675   length = 2;
676   while (va_arg (ap, char *))
677     length++;
678   va_end (ap);
679
680   args = alloca (length * sizeof (void *));
681   args[0] = (char *) arg;
682   for (i = 1; i < length; i++)
683     args[i] = va_arg (aq, char *);
684   envp = va_arg (aq, char **);
685   va_end (aq);
686
687   return execve (path, args, envp);
688 }
689 #endif
690
691 #ifdef L_gcov_execv
692 /* A wrapper for the execv function.  Flushes the accumulated profiling data, so
693    that they are not lost.  */
694
695 int
696 __gcov_execv (const char *path, char *const argv[])
697 {
698   __gcov_flush ();
699   return execv (path, argv);
700 }
701 #endif
702
703 #ifdef L_gcov_execvp
704 /* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
705    that they are not lost.  */
706
707 int
708 __gcov_execvp (const char *path, char *const argv[])
709 {
710   __gcov_flush ();
711   return execvp (path, argv);
712 }
713 #endif
714
715 #ifdef L_gcov_execve
716 /* A wrapper for the execve function.  Flushes the accumulated profiling data, so
717    that they are not lost.  */
718
719 int
720 __gcov_execve (const char *path, char *const argv[], char *const envp[])
721 {
722   __gcov_flush ();
723   return execve (path, argv, envp);
724 }
725 #endif
726 #endif /* inhibit_libc */