2005-04-29 Jim Tison <jtison@us.ibm.com>
[official-gcc.git] / gcc / libgcov.c
blob054d1e0a3de1d5ef9567a471e13f05cb90b10faa
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.
6 This file is part of GCC.
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.
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.)
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.
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. */
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. */
36 #include "tconfig.h"
37 #include "tsystem.h"
38 #include "coretypes.h"
39 #include "tm.h"
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"
53 #if defined(inhibit_libc)
54 /* If libc and its header files are not available, provide dummy functions. */
56 #ifdef L_gcov
57 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
58 void __gcov_flush (void) {}
59 #endif
61 #ifdef L_gcov_merge_add
62 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
63 unsigned n_counters __attribute__ ((unused))) {}
64 #endif
66 #ifdef L_gcov_merge_single
67 void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
68 unsigned n_counters __attribute__ ((unused))) {}
69 #endif
71 #ifdef L_gcov_merge_delta
72 void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
73 unsigned n_counters __attribute__ ((unused))) {}
74 #endif
76 #else
78 #include <string.h>
79 #if GCOV_LOCKED
80 #include <fcntl.h>
81 #include <errno.h>
82 #include <sys/stat.h>
83 #endif
85 #ifdef L_gcov
86 #include "gcov-io.c"
88 /* Chain of per-object gcov structures. */
89 static struct gcov_info *gcov_list;
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;
95 static int
96 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
98 if (version != GCOV_VERSION)
100 char v[4], e[4];
102 GCOV_UNSIGNED2STRING (v, version);
103 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
105 fprintf (stderr,
106 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
107 ptr->filename, e, v);
108 return 0;
110 return 1;
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. */
120 static void
121 gcov_exit (void)
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;
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)
136 ci_ptr = gi_ptr->counts;
137 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
139 if (!((1 << t_ix) & gi_ptr->ctr_mask))
140 continue;
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++)
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];
150 ci_ptr++;
154 /* Now merge each file. */
155 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
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;
169 memset (&this_object, 0, sizeof (this_object));
170 memset (&object, 0, sizeof (object));
172 /* Totals for this object file. */
173 ci_ptr = gi_ptr->counts;
174 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
176 if (!((1 << t_ix) & gi_ptr->ctr_mask))
177 continue;
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++)
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];
188 ci_ptr++;
191 c_ix = 0;
192 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
193 if ((1 << t_ix) & gi_ptr->ctr_mask)
195 values[c_ix] = gi_ptr->counts[c_ix].values;
196 c_ix++;
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))
204 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
205 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
208 if (!gcov_open (gi_ptr->filename))
210 fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
211 continue;
214 tag = gcov_read_unsigned ();
215 if (tag)
217 /* Merge data from file. */
218 if (tag != GCOV_DATA_MAGIC)
220 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
221 gi_ptr->filename);
222 goto read_fatal;
224 length = gcov_read_unsigned ();
225 if (!gcov_version (gi_ptr, length))
226 goto read_fatal;
228 length = gcov_read_unsigned ();
229 if (length != gi_ptr->stamp)
230 /* Read from a different compilation. Overwrite the file. */
231 goto rewrite;
233 /* Merge execution counts for each function. */
234 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
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 ();
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)
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;
254 c_ix = 0;
255 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
257 gcov_merge_fn merge;
259 if (!((1 << t_ix) & gi_ptr->ctr_mask))
260 continue;
262 n_counts = fi_ptr->n_ctrs[c_ix];
263 merge = gi_ptr->counts[c_ix].merge;
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++;
274 if ((error = gcov_is_error ()))
275 goto read_error;
278 f_ix = ~0u;
279 /* Check program & object summary */
280 while (1)
282 int is_program;
284 eof_pos = gcov_position ();
285 tag = gcov_read_unsigned ();
286 if (!tag)
287 break;
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)
299 summary_pos = eof_pos;
300 goto rewrite;
304 goto rewrite;
306 read_error:;
307 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
308 : "profiling:%s:Error merging\n", gi_ptr->filename);
310 read_fatal:;
311 gcov_close ();
312 continue;
314 rewrite:;
315 gcov_rewrite ();
316 if (!summary_pos)
317 memset (&program, 0, sizeof (program));
319 /* Merge the summaries. */
320 f_ix = ~0u;
321 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
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];
329 if ((1 << t_ix) & gi_ptr->ctr_mask)
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;
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;
349 else if (cs_obj->num || cs_prg->num)
350 goto read_mismatch;
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)))
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;
365 c_ix = 0;
366 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
367 if ((1 << t_ix) & gi_ptr->ctr_mask)
369 values[c_ix] = gi_ptr->counts[c_ix].values;
370 c_ix++;
373 program.checksum = gcov_crc32;
375 /* Write out the data. */
376 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
377 gcov_write_unsigned (gi_ptr->stamp);
379 /* Write execution counts for each function. */
380 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
382 fi_ptr = (const struct gcov_fn_info *)
383 ((const char *) gi_ptr->functions + f_ix * fi_stride);
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);
390 c_ix = 0;
391 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
393 gcov_type *c_ptr;
395 if (!((1 << t_ix) & gi_ptr->ctr_mask))
396 continue;
398 n_counts = fi_ptr->n_ctrs[c_ix];
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++);
406 values[c_ix] = c_ptr;
407 c_ix++;
411 /* Object file summary. */
412 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
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);
428 /* Add a new object file onto the bb chain. Invoked automatically
429 when running an object file's global ctors. */
431 void
432 __gcov_init (struct gcov_info *info)
434 if (!info->version)
435 return;
436 if (gcov_version (info, info->version))
438 const char *ptr = info->filename;
439 gcov_unsigned_t crc32 = gcov_crc32;
443 unsigned ix;
444 gcov_unsigned_t value = *ptr << 24;
446 for (ix = 8; ix--; value <<= 1)
448 gcov_unsigned_t feedback;
450 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
451 crc32 <<= 1;
452 crc32 ^= feedback;
455 while (*ptr++);
457 gcov_crc32 = crc32;
459 if (!gcov_list)
460 atexit (gcov_exit);
462 info->next = gcov_list;
463 gcov_list = info;
465 info->version = 0;
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. */
472 void
473 __gcov_flush (void)
475 const struct gcov_info *gi_ptr;
477 gcov_exit ();
478 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
480 unsigned t_ix;
481 const struct gcov_ctr_info *ci_ptr;
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)
486 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
487 ci_ptr++;
492 #endif /* L_gcov */
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)
501 for (; n_counters; counters++, n_counters--)
502 *counters += gcov_read_counter ();
504 #endif /* L_gcov_merge_add */
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:
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)
519 unsigned i, n_measures;
520 gcov_type value, counter, all;
522 gcc_assert (!(n_counters % 3));
523 n_measures = n_counters / 3;
524 for (i = 0; i < n_measures; i++, counters += 3)
526 value = gcov_read_counter ();
527 counter = gcov_read_counter ();
528 all = gcov_read_counter ();
530 if (counters[0] == value)
531 counters[1] += counter;
532 else if (counter > counters[1])
534 counters[0] = value;
535 counters[1] = counter - counters[1];
537 else
538 counters[1] -= counter;
539 counters[2] += all;
542 #endif /* L_gcov_merge_single */
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:
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)
558 unsigned i, n_measures;
559 gcov_type last, value, counter, all;
561 gcc_assert (!(n_counters % 4));
562 n_measures = n_counters / 4;
563 for (i = 0; i < n_measures; i++, counters += 4)
565 last = gcov_read_counter ();
566 value = gcov_read_counter ();
567 counter = gcov_read_counter ();
568 all = gcov_read_counter ();
570 if (counters[1] == value)
571 counters[2] += counter;
572 else if (counter > counters[2])
574 counters[1] = value;
575 counters[2] = counter - counters[2];
577 else
578 counters[2] -= counter;
579 counters[3] += all;
582 #endif /* L_gcov_merge_delta */
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. */
590 void
591 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
592 int start, unsigned steps)
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]++;
602 #endif
604 #ifdef L_gcov_pow2_profiler
605 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
606 COUNTERS[0] is incremented. */
608 void
609 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
611 if (value & (value - 1))
612 counters[0]++;
613 else
614 counters[1]++;
616 #endif
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.
627 In any case, COUNTERS[2] is incremented. */
629 void
630 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
632 if (value == counters[0])
633 counters[1]++;
634 else if (counters[1] == 0)
636 counters[1] = 1;
637 counters[0] = value;
639 else
640 counters[1]--;
641 counters[2]++;
643 #endif
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. */
649 pid_t
650 __gcov_fork (void)
652 __gcov_flush ();
653 return fork ();
655 #endif
657 #ifdef L_gcov_execl
658 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
659 that they are not lost. */
662 __gcov_execl (const char *path, const char *arg, ...)
664 va_list ap, aq;
665 unsigned i, length;
666 char **args;
668 __gcov_flush ();
670 va_start (ap, arg);
671 va_copy (aq, ap);
673 length = 2;
674 while (va_arg (ap, char *))
675 length++;
676 va_end (ap);
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);
684 return execv (path, args);
686 #endif
688 #ifdef L_gcov_execlp
689 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so
690 that they are not lost. */
693 __gcov_execlp (const char *path, const char *arg, ...)
695 va_list ap, aq;
696 unsigned i, length;
697 char **args;
699 __gcov_flush ();
701 va_start (ap, arg);
702 va_copy (aq, ap);
704 length = 2;
705 while (va_arg (ap, char *))
706 length++;
707 va_end (ap);
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);
715 return execvp (path, args);
717 #endif
719 #ifdef L_gcov_execle
720 /* A wrapper for the execle function. Flushes the accumulated profiling data, so
721 that they are not lost. */
724 __gcov_execle (const char *path, const char *arg, ...)
726 va_list ap, aq;
727 unsigned i, length;
728 char **args;
729 char **envp;
731 __gcov_flush ();
733 va_start (ap, arg);
734 va_copy (aq, ap);
736 length = 2;
737 while (va_arg (ap, char *))
738 length++;
739 va_end (ap);
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);
748 return execve (path, args, envp);
750 #endif
752 #ifdef L_gcov_execv
753 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
754 that they are not lost. */
757 __gcov_execv (const char *path, char *const argv[])
759 __gcov_flush ();
760 return execv (path, argv);
762 #endif
764 #ifdef L_gcov_execvp
765 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so
766 that they are not lost. */
769 __gcov_execvp (const char *path, char *const argv[])
771 __gcov_flush ();
772 return execvp (path, argv);
774 #endif
776 #ifdef L_gcov_execve
777 /* A wrapper for the execve function. Flushes the accumulated profiling data, so
778 that they are not lost. */
781 __gcov_execve (const char *path, char *const argv[], char *const envp[])
783 __gcov_flush ();
784 return execve (path, argv, envp);
786 #endif
787 #endif /* inhibit_libc */