xref: /openbsd/gnu/gcc/gcc/libgcov.c (revision 2a970957)
1404b540aSrobert /* Routines required for instrumenting a program.  */
2404b540aSrobert /* Compile this one with gcc.  */
3404b540aSrobert /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4404b540aSrobert    2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
5404b540aSrobert 
6404b540aSrobert This file is part of GCC.
7404b540aSrobert 
8404b540aSrobert GCC is free software; you can redistribute it and/or modify it under
9404b540aSrobert the terms of the GNU General Public License as published by the Free
10404b540aSrobert Software Foundation; either version 2, or (at your option) any later
11404b540aSrobert version.
12404b540aSrobert 
13404b540aSrobert In addition to the permissions in the GNU General Public License, the
14404b540aSrobert Free Software Foundation gives you unlimited permission to link the
15404b540aSrobert compiled version of this file into combinations with other programs,
16404b540aSrobert and to distribute those combinations without any restriction coming
17404b540aSrobert from the use of this file.  (The General Public License restrictions
18404b540aSrobert do apply in other respects; for example, they cover modification of
19404b540aSrobert the file, and distribution when not linked into a combine
20404b540aSrobert executable.)
21404b540aSrobert 
22404b540aSrobert GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23404b540aSrobert WARRANTY; without even the implied warranty of MERCHANTABILITY or
24404b540aSrobert FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25404b540aSrobert for more details.
26404b540aSrobert 
27404b540aSrobert You should have received a copy of the GNU General Public License
28404b540aSrobert along with GCC; see the file COPYING.  If not, write to the Free
29404b540aSrobert Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30404b540aSrobert 02110-1301, USA.  */
31404b540aSrobert 
32404b540aSrobert #include "tconfig.h"
33404b540aSrobert #include "tsystem.h"
34404b540aSrobert #include "coretypes.h"
35404b540aSrobert #include "tm.h"
36404b540aSrobert 
37404b540aSrobert #if defined(inhibit_libc)
38404b540aSrobert #define IN_LIBGCOV (-1)
39404b540aSrobert #else
40404b540aSrobert #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
41404b540aSrobert #include <stdio.h>
42404b540aSrobert #define IN_LIBGCOV 1
43404b540aSrobert #if defined(L_gcov)
44404b540aSrobert #define GCOV_LINKAGE /* nothing */
45404b540aSrobert #endif
46404b540aSrobert #endif
47404b540aSrobert #include "gcov-io.h"
48404b540aSrobert 
49404b540aSrobert #if defined(inhibit_libc)
50404b540aSrobert /* If libc and its header files are not available, provide dummy functions.  */
51404b540aSrobert 
52404b540aSrobert #ifdef L_gcov
__gcov_init(struct gcov_info * p)53404b540aSrobert void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
__gcov_flush(void)54404b540aSrobert void __gcov_flush (void) {}
55404b540aSrobert #endif
56404b540aSrobert 
57404b540aSrobert #ifdef L_gcov_merge_add
__gcov_merge_add(gcov_type * counters,unsigned n_counters)58404b540aSrobert void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
59404b540aSrobert 		       unsigned n_counters __attribute__ ((unused))) {}
60404b540aSrobert #endif
61404b540aSrobert 
62404b540aSrobert #ifdef L_gcov_merge_single
__gcov_merge_single(gcov_type * counters,unsigned n_counters)63404b540aSrobert void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
64404b540aSrobert 			  unsigned n_counters __attribute__ ((unused))) {}
65404b540aSrobert #endif
66404b540aSrobert 
67404b540aSrobert #ifdef L_gcov_merge_delta
__gcov_merge_delta(gcov_type * counters,unsigned n_counters)68404b540aSrobert void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
69404b540aSrobert 			 unsigned n_counters __attribute__ ((unused))) {}
70404b540aSrobert #endif
71404b540aSrobert 
72404b540aSrobert #else
73404b540aSrobert 
74404b540aSrobert #include <string.h>
75404b540aSrobert #if GCOV_LOCKED
76404b540aSrobert #include <fcntl.h>
77404b540aSrobert #include <errno.h>
78404b540aSrobert #include <sys/stat.h>
79404b540aSrobert #endif
80404b540aSrobert 
81404b540aSrobert #ifdef L_gcov
82404b540aSrobert #include "gcov-io.c"
83404b540aSrobert 
84404b540aSrobert /* Chain of per-object gcov structures.  */
85404b540aSrobert static struct gcov_info *gcov_list;
86404b540aSrobert 
87404b540aSrobert /* A program checksum allows us to distinguish program data for an
88404b540aSrobert    object file included in multiple programs.  */
89404b540aSrobert static gcov_unsigned_t gcov_crc32;
90404b540aSrobert 
91404b540aSrobert /* Size of the longest file name. */
92404b540aSrobert static size_t gcov_max_filename = 0;
93404b540aSrobert 
94404b540aSrobert #ifdef TARGET_POSIX_IO
95404b540aSrobert /* Make sure path component of the given FILENAME exists, create
96404b540aSrobert    missing directories. FILENAME must be writable.
97404b540aSrobert    Returns zero on success, or -1 if an error occurred.  */
98404b540aSrobert 
99404b540aSrobert static int
create_file_directory(char * filename)100404b540aSrobert create_file_directory (char *filename)
101404b540aSrobert {
102404b540aSrobert   char *s;
103404b540aSrobert 
104404b540aSrobert   for (s = filename + 1; *s != '\0'; s++)
105404b540aSrobert     if (IS_DIR_SEPARATOR(*s))
106404b540aSrobert       {
107404b540aSrobert         char sep = *s;
108404b540aSrobert 	*s  = '\0';
109404b540aSrobert 
110404b540aSrobert         /* Try to make directory if it doesn't already exist.  */
111404b540aSrobert         if (access (filename, F_OK) == -1
112404b540aSrobert             && mkdir (filename, 0755) == -1
113404b540aSrobert             /* The directory might have been made by another process.  */
114404b540aSrobert 	    && errno != EEXIST)
115404b540aSrobert 	  {
116404b540aSrobert             fprintf (stderr, "profiling:%s:Cannot create directory\n",
117404b540aSrobert 		     filename);
118404b540aSrobert             *s = sep;
119404b540aSrobert 	    return -1;
120404b540aSrobert 	  };
121404b540aSrobert 
122404b540aSrobert 	*s = sep;
123404b540aSrobert       };
124404b540aSrobert   return 0;
125404b540aSrobert }
126404b540aSrobert #endif
127404b540aSrobert 
128404b540aSrobert /* Check if VERSION of the info block PTR matches libgcov one.
129404b540aSrobert    Return 1 on success, or zero in case of versions mismatch.
130404b540aSrobert    If FILENAME is not NULL, its value used for reporting purposes
131404b540aSrobert    instead of value from the info block.  */
132404b540aSrobert 
133404b540aSrobert static int
gcov_version(struct gcov_info * ptr,gcov_unsigned_t version,const char * filename)134404b540aSrobert gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
135404b540aSrobert 	      const char *filename)
136404b540aSrobert {
137404b540aSrobert   if (version != GCOV_VERSION)
138404b540aSrobert     {
139404b540aSrobert       char v[4], e[4];
140404b540aSrobert 
141404b540aSrobert       GCOV_UNSIGNED2STRING (v, version);
142404b540aSrobert       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
143404b540aSrobert 
144404b540aSrobert       fprintf (stderr,
145404b540aSrobert 	       "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
146404b540aSrobert 	       filename? filename : ptr->filename, e, v);
147404b540aSrobert       return 0;
148404b540aSrobert     }
149404b540aSrobert   return 1;
150404b540aSrobert }
151404b540aSrobert 
152404b540aSrobert /* Dump the coverage counts. We merge with existing counts when
153404b540aSrobert    possible, to avoid growing the .da files ad infinitum. We use this
154404b540aSrobert    program's checksum to make sure we only accumulate whole program
155404b540aSrobert    statistics to the correct summary. An object file might be embedded
156404b540aSrobert    in two separate programs, and we must keep the two program
157404b540aSrobert    summaries separate.  */
158404b540aSrobert 
159404b540aSrobert static void
gcov_exit(void)160404b540aSrobert gcov_exit (void)
161404b540aSrobert {
162404b540aSrobert   struct gcov_info *gi_ptr;
163404b540aSrobert   struct gcov_summary this_program;
164404b540aSrobert   struct gcov_summary all;
165404b540aSrobert   struct gcov_ctr_summary *cs_ptr;
166404b540aSrobert   const struct gcov_ctr_info *ci_ptr;
167404b540aSrobert   unsigned t_ix;
168404b540aSrobert   gcov_unsigned_t c_num;
169404b540aSrobert   const char *gcov_prefix;
170404b540aSrobert   int gcov_prefix_strip = 0;
171404b540aSrobert   size_t prefix_length;
172404b540aSrobert   char *gi_filename, *gi_filename_up;
173404b540aSrobert 
174404b540aSrobert   memset (&all, 0, sizeof (all));
175404b540aSrobert   /* Find the totals for this execution.  */
176404b540aSrobert   memset (&this_program, 0, sizeof (this_program));
177404b540aSrobert   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
178404b540aSrobert     {
179404b540aSrobert       ci_ptr = gi_ptr->counts;
180404b540aSrobert       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
181404b540aSrobert 	{
182404b540aSrobert 	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
183404b540aSrobert 	    continue;
184404b540aSrobert 
185404b540aSrobert 	  cs_ptr = &this_program.ctrs[t_ix];
186404b540aSrobert 	  cs_ptr->num += ci_ptr->num;
187404b540aSrobert 	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
188404b540aSrobert 	    {
189404b540aSrobert       	      cs_ptr->sum_all += ci_ptr->values[c_num];
190404b540aSrobert 	      if (cs_ptr->run_max < ci_ptr->values[c_num])
191404b540aSrobert 		cs_ptr->run_max = ci_ptr->values[c_num];
192404b540aSrobert 	    }
193404b540aSrobert 	  ci_ptr++;
194404b540aSrobert 	}
195404b540aSrobert     }
196404b540aSrobert 
197404b540aSrobert   /* Get file name relocation prefix.  Non-absolute values are ignored. */
198404b540aSrobert   gcov_prefix = getenv("GCOV_PREFIX");
199404b540aSrobert   if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
200404b540aSrobert     {
201404b540aSrobert       /* Check if the level of dirs to strip off specified. */
202404b540aSrobert       char *tmp = getenv("GCOV_PREFIX_STRIP");
203404b540aSrobert       if (tmp)
204404b540aSrobert         {
205404b540aSrobert           gcov_prefix_strip = atoi (tmp);
206404b540aSrobert           /* Do not consider negative values. */
207404b540aSrobert           if (gcov_prefix_strip < 0)
208404b540aSrobert             gcov_prefix_strip = 0;
209404b540aSrobert         }
210404b540aSrobert 
211404b540aSrobert       prefix_length = strlen(gcov_prefix);
212404b540aSrobert 
213404b540aSrobert       /* Remove an unnecessary trailing '/' */
214404b540aSrobert       if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
215404b540aSrobert 	prefix_length--;
216404b540aSrobert     }
217404b540aSrobert   else
218404b540aSrobert     prefix_length = 0;
219404b540aSrobert 
220404b540aSrobert   /* Allocate and initialize the filename scratch space.  */
221404b540aSrobert   gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1);
222404b540aSrobert   if (prefix_length)
223404b540aSrobert     memcpy (gi_filename, gcov_prefix, prefix_length);
224404b540aSrobert   gi_filename_up = gi_filename + prefix_length;
225404b540aSrobert 
226404b540aSrobert   /* Now merge each file.  */
227404b540aSrobert   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
228404b540aSrobert     {
229404b540aSrobert       struct gcov_summary this_object;
230404b540aSrobert       struct gcov_summary object, program;
231404b540aSrobert       gcov_type *values[GCOV_COUNTERS];
232404b540aSrobert       const struct gcov_fn_info *fi_ptr;
233404b540aSrobert       unsigned fi_stride;
234404b540aSrobert       unsigned c_ix, f_ix, n_counts;
235404b540aSrobert       struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
236404b540aSrobert       int error = 0;
237404b540aSrobert       gcov_unsigned_t tag, length;
238404b540aSrobert       gcov_position_t summary_pos = 0;
239404b540aSrobert       gcov_position_t eof_pos = 0;
240404b540aSrobert 
241404b540aSrobert       memset (&this_object, 0, sizeof (this_object));
242404b540aSrobert       memset (&object, 0, sizeof (object));
243404b540aSrobert 
244404b540aSrobert       /* Build relocated filename, stripping off leading
245404b540aSrobert          directories from the initial filename if requested. */
246404b540aSrobert       if (gcov_prefix_strip > 0)
247404b540aSrobert         {
248404b540aSrobert           int level = 0;
249404b540aSrobert           const char *fname = gi_ptr->filename;
250404b540aSrobert           const char *s;
251404b540aSrobert 
252404b540aSrobert           /* Skip selected directory levels. */
253404b540aSrobert 	  for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
254404b540aSrobert 	    if (IS_DIR_SEPARATOR(*s))
255404b540aSrobert 	      {
256404b540aSrobert 		fname = s;
257404b540aSrobert 		level++;
258404b540aSrobert 	      };
259404b540aSrobert 
260404b540aSrobert           /* Update complete filename with stripped original. */
261*2a970957Smiod           strlcpy (gi_filename_up, fname, gcov_max_filename + 1);
262404b540aSrobert         }
263404b540aSrobert       else
264*2a970957Smiod         strlcpy (gi_filename_up, gi_ptr->filename, gcov_max_filename + 1);
265404b540aSrobert 
266404b540aSrobert       /* Totals for this object file.  */
267404b540aSrobert       ci_ptr = gi_ptr->counts;
268404b540aSrobert       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
269404b540aSrobert 	{
270404b540aSrobert 	  if (!((1 << t_ix) & gi_ptr->ctr_mask))
271404b540aSrobert 	    continue;
272404b540aSrobert 
273404b540aSrobert 	  cs_ptr = &this_object.ctrs[t_ix];
274404b540aSrobert 	  cs_ptr->num += ci_ptr->num;
275404b540aSrobert 	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
276404b540aSrobert 	    {
277404b540aSrobert 	      cs_ptr->sum_all += ci_ptr->values[c_num];
278404b540aSrobert 	      if (cs_ptr->run_max < ci_ptr->values[c_num])
279404b540aSrobert 		cs_ptr->run_max = ci_ptr->values[c_num];
280404b540aSrobert 	    }
281404b540aSrobert 
282404b540aSrobert 	  ci_ptr++;
283404b540aSrobert 	}
284404b540aSrobert 
285404b540aSrobert       c_ix = 0;
286404b540aSrobert       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
287404b540aSrobert 	if ((1 << t_ix) & gi_ptr->ctr_mask)
288404b540aSrobert 	  {
289404b540aSrobert 	    values[c_ix] = gi_ptr->counts[c_ix].values;
290404b540aSrobert 	    c_ix++;
291404b540aSrobert 	  }
292404b540aSrobert 
293404b540aSrobert       /* Calculate the function_info stride. This depends on the
294404b540aSrobert 	 number of counter types being measured.  */
295404b540aSrobert       fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
296404b540aSrobert       if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
297404b540aSrobert 	{
298404b540aSrobert 	  fi_stride += __alignof__ (struct gcov_fn_info) - 1;
299404b540aSrobert 	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
300404b540aSrobert 	}
301404b540aSrobert 
302404b540aSrobert       if (!gcov_open (gi_filename))
303404b540aSrobert 	{
304404b540aSrobert #ifdef TARGET_POSIX_IO
305404b540aSrobert 	  /* Open failed likely due to missed directory.
306404b540aSrobert 	     Create directory and retry to open file. */
307404b540aSrobert           if (create_file_directory (gi_filename))
308404b540aSrobert 	    {
309404b540aSrobert 	      fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
310404b540aSrobert 	      continue;
311404b540aSrobert 	    }
312404b540aSrobert #endif
313404b540aSrobert 	  if (!gcov_open (gi_filename))
314404b540aSrobert 	    {
315404b540aSrobert               fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
316404b540aSrobert 	      continue;
317404b540aSrobert 	    }
318404b540aSrobert 	}
319404b540aSrobert 
320404b540aSrobert       tag = gcov_read_unsigned ();
321404b540aSrobert       if (tag)
322404b540aSrobert 	{
323404b540aSrobert 	  /* Merge data from file.  */
324404b540aSrobert 	  if (tag != GCOV_DATA_MAGIC)
325404b540aSrobert 	    {
326404b540aSrobert 	      fprintf (stderr, "profiling:%s:Not a gcov data file\n",
327404b540aSrobert 		       gi_filename);
328404b540aSrobert 	      goto read_fatal;
329404b540aSrobert 	    }
330404b540aSrobert 	  length = gcov_read_unsigned ();
331404b540aSrobert 	  if (!gcov_version (gi_ptr, length, gi_filename))
332404b540aSrobert 	    goto read_fatal;
333404b540aSrobert 
334404b540aSrobert 	  length = gcov_read_unsigned ();
335404b540aSrobert 	  if (length != gi_ptr->stamp)
336404b540aSrobert 	    /* Read from a different compilation. Overwrite the file.  */
337404b540aSrobert 	    goto rewrite;
338404b540aSrobert 
339404b540aSrobert 	  /* Merge execution counts for each function.  */
340404b540aSrobert 	  for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
341404b540aSrobert 	    {
342404b540aSrobert 	      fi_ptr = (const struct gcov_fn_info *)
343404b540aSrobert 		      ((const char *) gi_ptr->functions + f_ix * fi_stride);
344404b540aSrobert 	      tag = gcov_read_unsigned ();
345404b540aSrobert 	      length = gcov_read_unsigned ();
346404b540aSrobert 
347404b540aSrobert 	      /* Check function.  */
348404b540aSrobert 	      if (tag != GCOV_TAG_FUNCTION
349404b540aSrobert 		  || length != GCOV_TAG_FUNCTION_LENGTH
350404b540aSrobert 		  || gcov_read_unsigned () != fi_ptr->ident
351404b540aSrobert 		  || gcov_read_unsigned () != fi_ptr->checksum)
352404b540aSrobert 		{
353404b540aSrobert 		read_mismatch:;
354404b540aSrobert 		  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
355404b540aSrobert 			   gi_filename,
356404b540aSrobert 			   f_ix + 1 ? "function" : "summaries");
357404b540aSrobert 		  goto read_fatal;
358404b540aSrobert 		}
359404b540aSrobert 
360404b540aSrobert 	      c_ix = 0;
361404b540aSrobert 	      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
362404b540aSrobert 		{
363404b540aSrobert 		  gcov_merge_fn merge;
364404b540aSrobert 
365404b540aSrobert 		  if (!((1 << t_ix) & gi_ptr->ctr_mask))
366404b540aSrobert 		    continue;
367404b540aSrobert 
368404b540aSrobert 		  n_counts = fi_ptr->n_ctrs[c_ix];
369404b540aSrobert 		  merge = gi_ptr->counts[c_ix].merge;
370404b540aSrobert 
371404b540aSrobert 		  tag = gcov_read_unsigned ();
372404b540aSrobert 		  length = gcov_read_unsigned ();
373404b540aSrobert 		  if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
374404b540aSrobert 		      || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
375404b540aSrobert 		    goto read_mismatch;
376404b540aSrobert 		  (*merge) (values[c_ix], n_counts);
377404b540aSrobert 		  values[c_ix] += n_counts;
378404b540aSrobert 		  c_ix++;
379404b540aSrobert 		}
380404b540aSrobert 	      if ((error = gcov_is_error ()))
381404b540aSrobert 		goto read_error;
382404b540aSrobert 	    }
383404b540aSrobert 
384404b540aSrobert 	  f_ix = ~0u;
385404b540aSrobert 	  /* Check program & object summary */
386404b540aSrobert 	  while (1)
387404b540aSrobert 	    {
388404b540aSrobert 	      int is_program;
389404b540aSrobert 
390404b540aSrobert 	      eof_pos = gcov_position ();
391404b540aSrobert 	      tag = gcov_read_unsigned ();
392404b540aSrobert 	      if (!tag)
393404b540aSrobert 		break;
394404b540aSrobert 
395404b540aSrobert 	      length = gcov_read_unsigned ();
396404b540aSrobert 	      is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
397404b540aSrobert 	      if (length != GCOV_TAG_SUMMARY_LENGTH
398404b540aSrobert 		  || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
399404b540aSrobert 		goto read_mismatch;
400404b540aSrobert 	      gcov_read_summary (is_program ? &program : &object);
401404b540aSrobert 	      if ((error = gcov_is_error ()))
402404b540aSrobert 		goto read_error;
403404b540aSrobert 	      if (is_program && program.checksum == gcov_crc32)
404404b540aSrobert 		{
405404b540aSrobert 		  summary_pos = eof_pos;
406404b540aSrobert 		  goto rewrite;
407404b540aSrobert 		}
408404b540aSrobert 	    }
409404b540aSrobert 	}
410404b540aSrobert       goto rewrite;
411404b540aSrobert 
412404b540aSrobert     read_error:;
413404b540aSrobert       fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
414404b540aSrobert 	       : "profiling:%s:Error merging\n", gi_filename);
415404b540aSrobert 
416404b540aSrobert     read_fatal:;
417404b540aSrobert       gcov_close ();
418404b540aSrobert       continue;
419404b540aSrobert 
420404b540aSrobert     rewrite:;
421404b540aSrobert       gcov_rewrite ();
422404b540aSrobert       if (!summary_pos)
423404b540aSrobert 	memset (&program, 0, sizeof (program));
424404b540aSrobert 
425404b540aSrobert       /* Merge the summaries.  */
426404b540aSrobert       f_ix = ~0u;
427404b540aSrobert       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
428404b540aSrobert 	{
429404b540aSrobert 	  cs_obj = &object.ctrs[t_ix];
430404b540aSrobert 	  cs_tobj = &this_object.ctrs[t_ix];
431404b540aSrobert 	  cs_prg = &program.ctrs[t_ix];
432404b540aSrobert 	  cs_tprg = &this_program.ctrs[t_ix];
433404b540aSrobert 	  cs_all = &all.ctrs[t_ix];
434404b540aSrobert 
435404b540aSrobert 	  if ((1 << t_ix) & gi_ptr->ctr_mask)
436404b540aSrobert 	    {
437404b540aSrobert 	      if (!cs_obj->runs++)
438404b540aSrobert 		cs_obj->num = cs_tobj->num;
439404b540aSrobert 	      else if (cs_obj->num != cs_tobj->num)
440404b540aSrobert 		goto read_mismatch;
441404b540aSrobert 	      cs_obj->sum_all += cs_tobj->sum_all;
442404b540aSrobert 	      if (cs_obj->run_max < cs_tobj->run_max)
443404b540aSrobert 		cs_obj->run_max = cs_tobj->run_max;
444404b540aSrobert 	      cs_obj->sum_max += cs_tobj->run_max;
445404b540aSrobert 
446404b540aSrobert 	      if (!cs_prg->runs++)
447404b540aSrobert 		cs_prg->num = cs_tprg->num;
448404b540aSrobert 	      else if (cs_prg->num != cs_tprg->num)
449404b540aSrobert 		goto read_mismatch;
450404b540aSrobert 	      cs_prg->sum_all += cs_tprg->sum_all;
451404b540aSrobert 	      if (cs_prg->run_max < cs_tprg->run_max)
452404b540aSrobert 		cs_prg->run_max = cs_tprg->run_max;
453404b540aSrobert 	      cs_prg->sum_max += cs_tprg->run_max;
454404b540aSrobert 	    }
455404b540aSrobert 	  else if (cs_obj->num || cs_prg->num)
456404b540aSrobert 	    goto read_mismatch;
457404b540aSrobert 
458404b540aSrobert 	  if (!cs_all->runs && cs_prg->runs)
459404b540aSrobert 	    memcpy (cs_all, cs_prg, sizeof (*cs_all));
460404b540aSrobert 	  else if (!all.checksum
461404b540aSrobert 		   && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
462404b540aSrobert 		   && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
463404b540aSrobert 	    {
464404b540aSrobert 	      fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
465404b540aSrobert 		       gi_filename, GCOV_LOCKED
466404b540aSrobert 		       ? "" : " or concurrent update without locking support");
467404b540aSrobert 	      all.checksum = ~0u;
468404b540aSrobert 	    }
469404b540aSrobert 	}
470404b540aSrobert 
471404b540aSrobert       c_ix = 0;
472404b540aSrobert       for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
473404b540aSrobert 	if ((1 << t_ix) & gi_ptr->ctr_mask)
474404b540aSrobert 	  {
475404b540aSrobert 	    values[c_ix] = gi_ptr->counts[c_ix].values;
476404b540aSrobert 	    c_ix++;
477404b540aSrobert 	  }
478404b540aSrobert 
479404b540aSrobert       program.checksum = gcov_crc32;
480404b540aSrobert 
481404b540aSrobert       /* Write out the data.  */
482404b540aSrobert       gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
483404b540aSrobert       gcov_write_unsigned (gi_ptr->stamp);
484404b540aSrobert 
485404b540aSrobert       /* Write execution counts for each function.  */
486404b540aSrobert       for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
487404b540aSrobert 	{
488404b540aSrobert 	  fi_ptr = (const struct gcov_fn_info *)
489404b540aSrobert 		  ((const char *) gi_ptr->functions + f_ix * fi_stride);
490404b540aSrobert 
491404b540aSrobert 	  /* Announce function.  */
492404b540aSrobert 	  gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
493404b540aSrobert 	  gcov_write_unsigned (fi_ptr->ident);
494404b540aSrobert 	  gcov_write_unsigned (fi_ptr->checksum);
495404b540aSrobert 
496404b540aSrobert 	  c_ix = 0;
497404b540aSrobert 	  for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
498404b540aSrobert 	    {
499404b540aSrobert 	      gcov_type *c_ptr;
500404b540aSrobert 
501404b540aSrobert 	      if (!((1 << t_ix) & gi_ptr->ctr_mask))
502404b540aSrobert 		continue;
503404b540aSrobert 
504404b540aSrobert 	      n_counts = fi_ptr->n_ctrs[c_ix];
505404b540aSrobert 
506404b540aSrobert 	      gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
507404b540aSrobert 				     GCOV_TAG_COUNTER_LENGTH (n_counts));
508404b540aSrobert 	      c_ptr = values[c_ix];
509404b540aSrobert 	      while (n_counts--)
510404b540aSrobert 		gcov_write_counter (*c_ptr++);
511404b540aSrobert 
512404b540aSrobert 	      values[c_ix] = c_ptr;
513404b540aSrobert 	      c_ix++;
514404b540aSrobert 	    }
515404b540aSrobert 	}
516404b540aSrobert 
517404b540aSrobert       /* Object file summary.  */
518404b540aSrobert       gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
519404b540aSrobert 
520404b540aSrobert       /* Generate whole program statistics.  */
521404b540aSrobert       if (eof_pos)
522404b540aSrobert 	gcov_seek (eof_pos);
523404b540aSrobert       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
524404b540aSrobert       if (!summary_pos)
525404b540aSrobert 	gcov_write_unsigned (0);
526404b540aSrobert       if ((error = gcov_close ()))
527404b540aSrobert 	  fprintf (stderr, error  < 0 ?
528404b540aSrobert 		   "profiling:%s:Overflow writing\n" :
529404b540aSrobert 		   "profiling:%s:Error writing\n",
530404b540aSrobert 		   gi_filename);
531404b540aSrobert     }
532404b540aSrobert }
533404b540aSrobert 
534404b540aSrobert /* Add a new object file onto the bb chain.  Invoked automatically
535404b540aSrobert    when running an object file's global ctors.  */
536404b540aSrobert 
537404b540aSrobert void
__gcov_init(struct gcov_info * info)538404b540aSrobert __gcov_init (struct gcov_info *info)
539404b540aSrobert {
540404b540aSrobert   if (!info->version)
541404b540aSrobert     return;
542404b540aSrobert   if (gcov_version (info, info->version, 0))
543404b540aSrobert     {
544404b540aSrobert       const char *ptr = info->filename;
545404b540aSrobert       gcov_unsigned_t crc32 = gcov_crc32;
546404b540aSrobert       size_t filename_length =  strlen(info->filename);
547404b540aSrobert 
548404b540aSrobert       /* Refresh the longest file name information */
549404b540aSrobert       if (filename_length > gcov_max_filename)
550404b540aSrobert         gcov_max_filename = filename_length;
551404b540aSrobert 
552404b540aSrobert       do
553404b540aSrobert 	{
554404b540aSrobert 	  unsigned ix;
555404b540aSrobert 	  gcov_unsigned_t value = *ptr << 24;
556404b540aSrobert 
557404b540aSrobert 	  for (ix = 8; ix--; value <<= 1)
558404b540aSrobert 	    {
559404b540aSrobert 	      gcov_unsigned_t feedback;
560404b540aSrobert 
561404b540aSrobert 	      feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
562404b540aSrobert 	      crc32 <<= 1;
563404b540aSrobert 	      crc32 ^= feedback;
564404b540aSrobert 	    }
565404b540aSrobert 	}
566404b540aSrobert       while (*ptr++);
567404b540aSrobert 
568404b540aSrobert       gcov_crc32 = crc32;
569404b540aSrobert 
570404b540aSrobert       if (!gcov_list)
571404b540aSrobert 	atexit (gcov_exit);
572404b540aSrobert 
573404b540aSrobert       info->next = gcov_list;
574404b540aSrobert       gcov_list = info;
575404b540aSrobert     }
576404b540aSrobert   info->version = 0;
577404b540aSrobert }
578404b540aSrobert 
579404b540aSrobert /* Called before fork or exec - write out profile information gathered so
580404b540aSrobert    far and reset it to zero.  This avoids duplication or loss of the
581404b540aSrobert    profile information gathered so far.  */
582404b540aSrobert 
583404b540aSrobert void
__gcov_flush(void)584404b540aSrobert __gcov_flush (void)
585404b540aSrobert {
586404b540aSrobert   const struct gcov_info *gi_ptr;
587404b540aSrobert 
588404b540aSrobert   gcov_exit ();
589404b540aSrobert   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
590404b540aSrobert     {
591404b540aSrobert       unsigned t_ix;
592404b540aSrobert       const struct gcov_ctr_info *ci_ptr;
593404b540aSrobert 
594404b540aSrobert       for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
595404b540aSrobert 	if ((1 << t_ix) & gi_ptr->ctr_mask)
596404b540aSrobert 	  {
597404b540aSrobert 	    memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
598404b540aSrobert 	    ci_ptr++;
599404b540aSrobert 	  }
600404b540aSrobert     }
601404b540aSrobert }
602404b540aSrobert 
603404b540aSrobert #endif /* L_gcov */
604404b540aSrobert 
605404b540aSrobert #ifdef L_gcov_merge_add
606404b540aSrobert /* The profile merging function that just adds the counters.  It is given
607404b540aSrobert    an array COUNTERS of N_COUNTERS old counters and it reads the same number
608404b540aSrobert    of counters from the gcov file.  */
609404b540aSrobert void
__gcov_merge_add(gcov_type * counters,unsigned n_counters)610404b540aSrobert __gcov_merge_add (gcov_type *counters, unsigned n_counters)
611404b540aSrobert {
612404b540aSrobert   for (; n_counters; counters++, n_counters--)
613404b540aSrobert     *counters += gcov_read_counter ();
614404b540aSrobert }
615404b540aSrobert #endif /* L_gcov_merge_add */
616404b540aSrobert 
617404b540aSrobert #ifdef L_gcov_merge_single
618404b540aSrobert /* The profile merging function for choosing the most common value.
619404b540aSrobert    It is given an array COUNTERS of N_COUNTERS old counters and it
620404b540aSrobert    reads the same number of counters from the gcov file.  The counters
621404b540aSrobert    are split into 3-tuples where the members of the tuple have
622404b540aSrobert    meanings:
623404b540aSrobert 
624404b540aSrobert    -- the stored candidate on the most common value of the measured entity
625404b540aSrobert    -- counter
626404b540aSrobert    -- total number of evaluations of the value  */
627404b540aSrobert void
__gcov_merge_single(gcov_type * counters,unsigned n_counters)628404b540aSrobert __gcov_merge_single (gcov_type *counters, unsigned n_counters)
629404b540aSrobert {
630404b540aSrobert   unsigned i, n_measures;
631404b540aSrobert   gcov_type value, counter, all;
632404b540aSrobert 
633404b540aSrobert   gcc_assert (!(n_counters % 3));
634404b540aSrobert   n_measures = n_counters / 3;
635404b540aSrobert   for (i = 0; i < n_measures; i++, counters += 3)
636404b540aSrobert     {
637404b540aSrobert       value = gcov_read_counter ();
638404b540aSrobert       counter = gcov_read_counter ();
639404b540aSrobert       all = gcov_read_counter ();
640404b540aSrobert 
641404b540aSrobert       if (counters[0] == value)
642404b540aSrobert 	counters[1] += counter;
643404b540aSrobert       else if (counter > counters[1])
644404b540aSrobert 	{
645404b540aSrobert 	  counters[0] = value;
646404b540aSrobert 	  counters[1] = counter - counters[1];
647404b540aSrobert 	}
648404b540aSrobert       else
649404b540aSrobert 	counters[1] -= counter;
650404b540aSrobert       counters[2] += all;
651404b540aSrobert     }
652404b540aSrobert }
653404b540aSrobert #endif /* L_gcov_merge_single */
654404b540aSrobert 
655404b540aSrobert #ifdef L_gcov_merge_delta
656404b540aSrobert /* The profile merging function for choosing the most common
657404b540aSrobert    difference between two consecutive evaluations of the value.  It is
658404b540aSrobert    given an array COUNTERS of N_COUNTERS old counters and it reads the
659404b540aSrobert    same number of counters from the gcov file.  The counters are split
660404b540aSrobert    into 4-tuples where the members of the tuple have meanings:
661404b540aSrobert 
662404b540aSrobert    -- the last value of the measured entity
663404b540aSrobert    -- the stored candidate on the most common difference
664404b540aSrobert    -- counter
665404b540aSrobert    -- total number of evaluations of the value  */
666404b540aSrobert void
__gcov_merge_delta(gcov_type * counters,unsigned n_counters)667404b540aSrobert __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
668404b540aSrobert {
669404b540aSrobert   unsigned i, n_measures;
670404b540aSrobert   gcov_type last, value, counter, all;
671404b540aSrobert 
672404b540aSrobert   gcc_assert (!(n_counters % 4));
673404b540aSrobert   n_measures = n_counters / 4;
674404b540aSrobert   for (i = 0; i < n_measures; i++, counters += 4)
675404b540aSrobert     {
676404b540aSrobert       last = gcov_read_counter ();
677404b540aSrobert       value = gcov_read_counter ();
678404b540aSrobert       counter = gcov_read_counter ();
679404b540aSrobert       all = gcov_read_counter ();
680404b540aSrobert 
681404b540aSrobert       if (counters[1] == value)
682404b540aSrobert 	counters[2] += counter;
683404b540aSrobert       else if (counter > counters[2])
684404b540aSrobert 	{
685404b540aSrobert 	  counters[1] = value;
686404b540aSrobert 	  counters[2] = counter - counters[2];
687404b540aSrobert 	}
688404b540aSrobert       else
689404b540aSrobert 	counters[2] -= counter;
690404b540aSrobert       counters[3] += all;
691404b540aSrobert     }
692404b540aSrobert }
693404b540aSrobert #endif /* L_gcov_merge_delta */
694404b540aSrobert 
695404b540aSrobert #ifdef L_gcov_interval_profiler
696404b540aSrobert /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
697404b540aSrobert    corresponding counter in COUNTERS.  If the VALUE is above or below
698404b540aSrobert    the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
699404b540aSrobert    instead.  */
700404b540aSrobert 
701404b540aSrobert void
__gcov_interval_profiler(gcov_type * counters,gcov_type value,int start,unsigned steps)702404b540aSrobert __gcov_interval_profiler (gcov_type *counters, gcov_type value,
703404b540aSrobert 			  int start, unsigned steps)
704404b540aSrobert {
705404b540aSrobert   gcov_type delta = value - start;
706404b540aSrobert   if (delta < 0)
707404b540aSrobert     counters[steps + 1]++;
708404b540aSrobert   else if (delta >= steps)
709404b540aSrobert     counters[steps]++;
710404b540aSrobert   else
711404b540aSrobert     counters[delta]++;
712404b540aSrobert }
713404b540aSrobert #endif
714404b540aSrobert 
715404b540aSrobert #ifdef L_gcov_pow2_profiler
716404b540aSrobert /* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
717404b540aSrobert    COUNTERS[0] is incremented.  */
718404b540aSrobert 
719404b540aSrobert void
__gcov_pow2_profiler(gcov_type * counters,gcov_type value)720404b540aSrobert __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
721404b540aSrobert {
722404b540aSrobert   if (value & (value - 1))
723404b540aSrobert     counters[0]++;
724404b540aSrobert   else
725404b540aSrobert     counters[1]++;
726404b540aSrobert }
727404b540aSrobert #endif
728404b540aSrobert 
729404b540aSrobert #ifdef L_gcov_one_value_profiler
730404b540aSrobert /* Tries to determine the most common value among its inputs.  Checks if the
731404b540aSrobert    value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
732404b540aSrobert    is incremented.  If this is not the case and COUNTERS[1] is not zero,
733404b540aSrobert    COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
734404b540aSrobert    VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
735404b540aSrobert    function is called more than 50% of the time with one value, this value
736404b540aSrobert    will be in COUNTERS[0] in the end.
737404b540aSrobert 
738404b540aSrobert    In any case, COUNTERS[2] is incremented.  */
739404b540aSrobert 
740404b540aSrobert void
__gcov_one_value_profiler(gcov_type * counters,gcov_type value)741404b540aSrobert __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
742404b540aSrobert {
743404b540aSrobert   if (value == counters[0])
744404b540aSrobert     counters[1]++;
745404b540aSrobert   else if (counters[1] == 0)
746404b540aSrobert     {
747404b540aSrobert       counters[1] = 1;
748404b540aSrobert       counters[0] = value;
749404b540aSrobert     }
750404b540aSrobert   else
751404b540aSrobert     counters[1]--;
752404b540aSrobert   counters[2]++;
753404b540aSrobert }
754404b540aSrobert #endif
755404b540aSrobert 
756404b540aSrobert #ifdef L_gcov_fork
757404b540aSrobert /* A wrapper for the fork function.  Flushes the accumulated profiling data, so
758404b540aSrobert    that they are not counted twice.  */
759404b540aSrobert 
760404b540aSrobert pid_t
__gcov_fork(void)761404b540aSrobert __gcov_fork (void)
762404b540aSrobert {
763404b540aSrobert   __gcov_flush ();
764404b540aSrobert   return fork ();
765404b540aSrobert }
766404b540aSrobert #endif
767404b540aSrobert 
768404b540aSrobert #ifdef L_gcov_execl
769404b540aSrobert /* A wrapper for the execl function.  Flushes the accumulated profiling data, so
770404b540aSrobert    that they are not lost.  */
771404b540aSrobert 
772404b540aSrobert int
__gcov_execl(const char * path,const char * arg,...)773404b540aSrobert __gcov_execl (const char *path, const char *arg, ...)
774404b540aSrobert {
775404b540aSrobert   va_list ap, aq;
776404b540aSrobert   unsigned i, length;
777404b540aSrobert   char **args;
778404b540aSrobert 
779404b540aSrobert   __gcov_flush ();
780404b540aSrobert 
781404b540aSrobert   va_start (ap, arg);
782404b540aSrobert   va_copy (aq, ap);
783404b540aSrobert 
784404b540aSrobert   length = 2;
785404b540aSrobert   while (va_arg (ap, char *))
786404b540aSrobert     length++;
787404b540aSrobert   va_end (ap);
788404b540aSrobert 
789404b540aSrobert   args = (char **) alloca (length * sizeof (void *));
790404b540aSrobert   args[0] = (char *) arg;
791404b540aSrobert   for (i = 1; i < length; i++)
792404b540aSrobert     args[i] = va_arg (aq, char *);
793404b540aSrobert   va_end (aq);
794404b540aSrobert 
795404b540aSrobert   return execv (path, args);
796404b540aSrobert }
797404b540aSrobert #endif
798404b540aSrobert 
799404b540aSrobert #ifdef L_gcov_execlp
800404b540aSrobert /* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
801404b540aSrobert    that they are not lost.  */
802404b540aSrobert 
803404b540aSrobert int
__gcov_execlp(const char * path,const char * arg,...)804404b540aSrobert __gcov_execlp (const char *path, const char *arg, ...)
805404b540aSrobert {
806404b540aSrobert   va_list ap, aq;
807404b540aSrobert   unsigned i, length;
808404b540aSrobert   char **args;
809404b540aSrobert 
810404b540aSrobert   __gcov_flush ();
811404b540aSrobert 
812404b540aSrobert   va_start (ap, arg);
813404b540aSrobert   va_copy (aq, ap);
814404b540aSrobert 
815404b540aSrobert   length = 2;
816404b540aSrobert   while (va_arg (ap, char *))
817404b540aSrobert     length++;
818404b540aSrobert   va_end (ap);
819404b540aSrobert 
820404b540aSrobert   args = (char **) alloca (length * sizeof (void *));
821404b540aSrobert   args[0] = (char *) arg;
822404b540aSrobert   for (i = 1; i < length; i++)
823404b540aSrobert     args[i] = va_arg (aq, char *);
824404b540aSrobert   va_end (aq);
825404b540aSrobert 
826404b540aSrobert   return execvp (path, args);
827404b540aSrobert }
828404b540aSrobert #endif
829404b540aSrobert 
830404b540aSrobert #ifdef L_gcov_execle
831404b540aSrobert /* A wrapper for the execle function.  Flushes the accumulated profiling data, so
832404b540aSrobert    that they are not lost.  */
833404b540aSrobert 
834404b540aSrobert int
__gcov_execle(const char * path,const char * arg,...)835404b540aSrobert __gcov_execle (const char *path, const char *arg, ...)
836404b540aSrobert {
837404b540aSrobert   va_list ap, aq;
838404b540aSrobert   unsigned i, length;
839404b540aSrobert   char **args;
840404b540aSrobert   char **envp;
841404b540aSrobert 
842404b540aSrobert   __gcov_flush ();
843404b540aSrobert 
844404b540aSrobert   va_start (ap, arg);
845404b540aSrobert   va_copy (aq, ap);
846404b540aSrobert 
847404b540aSrobert   length = 2;
848404b540aSrobert   while (va_arg (ap, char *))
849404b540aSrobert     length++;
850404b540aSrobert   va_end (ap);
851404b540aSrobert 
852404b540aSrobert   args = (char **) alloca (length * sizeof (void *));
853404b540aSrobert   args[0] = (char *) arg;
854404b540aSrobert   for (i = 1; i < length; i++)
855404b540aSrobert     args[i] = va_arg (aq, char *);
856404b540aSrobert   envp = va_arg (aq, char **);
857404b540aSrobert   va_end (aq);
858404b540aSrobert 
859404b540aSrobert   return execve (path, args, envp);
860404b540aSrobert }
861404b540aSrobert #endif
862404b540aSrobert 
863404b540aSrobert #ifdef L_gcov_execv
864404b540aSrobert /* A wrapper for the execv function.  Flushes the accumulated profiling data, so
865404b540aSrobert    that they are not lost.  */
866404b540aSrobert 
867404b540aSrobert int
__gcov_execv(const char * path,char * const argv[])868404b540aSrobert __gcov_execv (const char *path, char *const argv[])
869404b540aSrobert {
870404b540aSrobert   __gcov_flush ();
871404b540aSrobert   return execv (path, argv);
872404b540aSrobert }
873404b540aSrobert #endif
874404b540aSrobert 
875404b540aSrobert #ifdef L_gcov_execvp
876404b540aSrobert /* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
877404b540aSrobert    that they are not lost.  */
878404b540aSrobert 
879404b540aSrobert int
__gcov_execvp(const char * path,char * const argv[])880404b540aSrobert __gcov_execvp (const char *path, char *const argv[])
881404b540aSrobert {
882404b540aSrobert   __gcov_flush ();
883404b540aSrobert   return execvp (path, argv);
884404b540aSrobert }
885404b540aSrobert #endif
886404b540aSrobert 
887404b540aSrobert #ifdef L_gcov_execve
888404b540aSrobert /* A wrapper for the execve function.  Flushes the accumulated profiling data, so
889404b540aSrobert    that they are not lost.  */
890404b540aSrobert 
891404b540aSrobert int
__gcov_execve(const char * path,char * const argv[],char * const envp[])892404b540aSrobert __gcov_execve (const char *path, char *const argv[], char *const envp[])
893404b540aSrobert {
894404b540aSrobert   __gcov_flush ();
895404b540aSrobert   return execve (path, argv, envp);
896404b540aSrobert }
897404b540aSrobert #endif
898404b540aSrobert #endif /* inhibit_libc */
899