* gcc.dg/const-elim-1.c: Remove xfail for xtensa-*-*.
[official-gcc.git] / gcc / libgcov.c
blob8b478a7707c4fa6431874093e6a2bfee22a1f064
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 #include "tconfig.h"
33 #include "tsystem.h"
34 #include "coretypes.h"
35 #include "tm.h"
37 #if defined(inhibit_libc)
38 #define IN_LIBGCOV (-1)
39 #else
40 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
41 #include <stdio.h>
42 #define IN_LIBGCOV 1
43 #if defined(L_gcov)
44 #define GCOV_LINKAGE /* nothing */
45 #endif
46 #endif
47 #include "gcov-io.h"
49 #if defined(inhibit_libc)
50 /* If libc and its header files are not available, provide dummy functions. */
52 #ifdef L_gcov
53 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
54 void __gcov_flush (void) {}
55 #endif
57 #ifdef L_gcov_merge_add
58 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
59 unsigned n_counters __attribute__ ((unused))) {}
60 #endif
62 #ifdef L_gcov_merge_single
63 void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
64 unsigned n_counters __attribute__ ((unused))) {}
65 #endif
67 #ifdef L_gcov_merge_delta
68 void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
69 unsigned n_counters __attribute__ ((unused))) {}
70 #endif
72 #else
74 #include <string.h>
75 #if GCOV_LOCKED
76 #include <fcntl.h>
77 #include <errno.h>
78 #include <sys/stat.h>
79 #endif
81 #ifdef L_gcov
82 #include "gcov-io.c"
84 /* Chain of per-object gcov structures. */
85 static struct gcov_info *gcov_list;
87 /* A program checksum allows us to distinguish program data for an
88 object file included in multiple programs. */
89 static gcov_unsigned_t gcov_crc32;
91 /* Size of the longest file name. */
92 static size_t gcov_max_filename = 0;
94 /* Make sure path compenent of the given FILENAME exists, create
95 missing directories. FILENAME must be writable.
96 Returns zero on success, or -1 if an error occurred. */
98 static int
99 create_file_directory (char *filename)
101 char *s;
103 for (s = filename + 1; *s != '\0'; s++)
104 if (IS_DIR_SEPARATOR(*s))
106 char sep = *s;
107 *s = '\0';
109 /* Try to make directory if it doesn't already exist. */
110 if (access (filename, F_OK) == -1
111 && mkdir (filename, 0755) == -1
112 /* The directory might have been made by another process. */
113 && errno != EEXIST)
115 fprintf (stderr, "profiling:%s:Cannot create directory\n",
116 filename);
117 *s = sep;
118 return -1;
121 *s = sep;
123 return 0;
126 /* Check if VERSION of the info block PTR matches libgcov one.
127 Return 1 on success, or zero in case of versions mismatch.
128 If FILENAME is not NULL, its value used for reporting purposes
129 instead of value from the info block. */
131 static int
132 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
133 const char *filename)
135 if (version != GCOV_VERSION)
137 char v[4], e[4];
139 GCOV_UNSIGNED2STRING (v, version);
140 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
142 fprintf (stderr,
143 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
144 filename? filename : ptr->filename, e, v);
145 return 0;
147 return 1;
150 /* Dump the coverage counts. We merge with existing counts when
151 possible, to avoid growing the .da files ad infinitum. We use this
152 program's checksum to make sure we only accumulate whole program
153 statistics to the correct summary. An object file might be embedded
154 in two separate programs, and we must keep the two program
155 summaries separate. */
157 static void
158 gcov_exit (void)
160 struct gcov_info *gi_ptr;
161 struct gcov_summary this_program;
162 struct gcov_summary all;
163 struct gcov_ctr_summary *cs_ptr;
164 const struct gcov_ctr_info *ci_ptr;
165 unsigned t_ix;
166 gcov_unsigned_t c_num;
167 const char *gcov_prefix;
168 int gcov_prefix_strip = 0;
169 size_t prefix_length;
170 char *gi_filename, *gi_filename_up;
172 memset (&all, 0, sizeof (all));
173 /* Find the totals for this execution. */
174 memset (&this_program, 0, sizeof (this_program));
175 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
177 ci_ptr = gi_ptr->counts;
178 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
180 if (!((1 << t_ix) & gi_ptr->ctr_mask))
181 continue;
183 cs_ptr = &this_program.ctrs[t_ix];
184 cs_ptr->num += ci_ptr->num;
185 for (c_num = 0; c_num < ci_ptr->num; c_num++)
187 cs_ptr->sum_all += ci_ptr->values[c_num];
188 if (cs_ptr->run_max < ci_ptr->values[c_num])
189 cs_ptr->run_max = ci_ptr->values[c_num];
191 ci_ptr++;
195 /* Get file name relocation prefix. Non-absolute values are ignored. */
196 gcov_prefix = getenv("GCOV_PREFIX");
197 if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
199 /* Check if the level of dirs to strip off specified. */
200 char *tmp = getenv("GCOV_PREFIX_STRIP");
201 if (tmp)
203 gcov_prefix_strip = atoi (tmp);
204 /* Do not consider negative values. */
205 if (gcov_prefix_strip < 0)
206 gcov_prefix_strip = 0;
209 prefix_length = strlen(gcov_prefix);
211 /* Remove an unneccesary trailing '/' */
212 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
213 prefix_length--;
216 /* Allocate and initialize the filename scratch space. */
217 gi_filename = alloca (prefix_length + gcov_max_filename + 1);
218 if (prefix_length)
219 memcpy (gi_filename, gcov_prefix, prefix_length);
220 gi_filename_up = gi_filename + prefix_length;
222 /* Now merge each file. */
223 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
225 struct gcov_summary this_object;
226 struct gcov_summary object, program;
227 gcov_type *values[GCOV_COUNTERS];
228 const struct gcov_fn_info *fi_ptr;
229 unsigned fi_stride;
230 unsigned c_ix, f_ix, n_counts;
231 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
232 int error = 0;
233 gcov_unsigned_t tag, length;
234 gcov_position_t summary_pos = 0;
235 gcov_position_t eof_pos = 0;
237 memset (&this_object, 0, sizeof (this_object));
238 memset (&object, 0, sizeof (object));
240 /* Build relocated filename, stripping off leading
241 directories from the initial filename if requested. */
242 if (gcov_prefix_strip > 0)
244 int level = 0;
245 const char *fname = gi_ptr->filename;
246 const char *s;
248 /* Skip selected directory levels. */
249 for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
250 if (IS_DIR_SEPARATOR(*s))
252 fname = s;
253 level++;
256 /* Update complete filename with stripped original. */
257 strcpy (gi_filename_up, fname);
259 else
260 strcpy (gi_filename_up, gi_ptr->filename);
262 /* Totals for this object file. */
263 ci_ptr = gi_ptr->counts;
264 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
266 if (!((1 << t_ix) & gi_ptr->ctr_mask))
267 continue;
269 cs_ptr = &this_object.ctrs[t_ix];
270 cs_ptr->num += ci_ptr->num;
271 for (c_num = 0; c_num < ci_ptr->num; c_num++)
273 cs_ptr->sum_all += ci_ptr->values[c_num];
274 if (cs_ptr->run_max < ci_ptr->values[c_num])
275 cs_ptr->run_max = ci_ptr->values[c_num];
278 ci_ptr++;
281 c_ix = 0;
282 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
283 if ((1 << t_ix) & gi_ptr->ctr_mask)
285 values[c_ix] = gi_ptr->counts[c_ix].values;
286 c_ix++;
289 /* Calculate the function_info stride. This depends on the
290 number of counter types being measured. */
291 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
292 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
294 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
295 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
298 if (!gcov_open (gi_filename))
300 /* Open failed likely due to missed directory.
301 Create directory and retry to open file. */
302 if (create_file_directory (gi_filename))
304 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
305 continue;
307 if (!gcov_open (gi_filename))
309 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
310 continue;
314 tag = gcov_read_unsigned ();
315 if (tag)
317 /* Merge data from file. */
318 if (tag != GCOV_DATA_MAGIC)
320 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
321 gi_filename);
322 goto read_fatal;
324 length = gcov_read_unsigned ();
325 if (!gcov_version (gi_ptr, length, gi_filename))
326 goto read_fatal;
328 length = gcov_read_unsigned ();
329 if (length != gi_ptr->stamp)
330 /* Read from a different compilation. Overwrite the file. */
331 goto rewrite;
333 /* Merge execution counts for each function. */
334 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
336 fi_ptr = (const struct gcov_fn_info *)
337 ((const char *) gi_ptr->functions + f_ix * fi_stride);
338 tag = gcov_read_unsigned ();
339 length = gcov_read_unsigned ();
341 /* Check function. */
342 if (tag != GCOV_TAG_FUNCTION
343 || length != GCOV_TAG_FUNCTION_LENGTH
344 || gcov_read_unsigned () != fi_ptr->ident
345 || gcov_read_unsigned () != fi_ptr->checksum)
347 read_mismatch:;
348 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
349 gi_filename,
350 f_ix + 1 ? "function" : "summaries");
351 goto read_fatal;
354 c_ix = 0;
355 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
357 gcov_merge_fn merge;
359 if (!((1 << t_ix) & gi_ptr->ctr_mask))
360 continue;
362 n_counts = fi_ptr->n_ctrs[c_ix];
363 merge = gi_ptr->counts[c_ix].merge;
365 tag = gcov_read_unsigned ();
366 length = gcov_read_unsigned ();
367 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
368 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
369 goto read_mismatch;
370 (*merge) (values[c_ix], n_counts);
371 values[c_ix] += n_counts;
372 c_ix++;
374 if ((error = gcov_is_error ()))
375 goto read_error;
378 f_ix = ~0u;
379 /* Check program & object summary */
380 while (1)
382 int is_program;
384 eof_pos = gcov_position ();
385 tag = gcov_read_unsigned ();
386 if (!tag)
387 break;
389 length = gcov_read_unsigned ();
390 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
391 if (length != GCOV_TAG_SUMMARY_LENGTH
392 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
393 goto read_mismatch;
394 gcov_read_summary (is_program ? &program : &object);
395 if ((error = gcov_is_error ()))
396 goto read_error;
397 if (is_program && program.checksum == gcov_crc32)
399 summary_pos = eof_pos;
400 goto rewrite;
404 goto rewrite;
406 read_error:;
407 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
408 : "profiling:%s:Error merging\n", gi_filename);
410 read_fatal:;
411 gcov_close ();
412 continue;
414 rewrite:;
415 gcov_rewrite ();
416 if (!summary_pos)
417 memset (&program, 0, sizeof (program));
419 /* Merge the summaries. */
420 f_ix = ~0u;
421 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
423 cs_obj = &object.ctrs[t_ix];
424 cs_tobj = &this_object.ctrs[t_ix];
425 cs_prg = &program.ctrs[t_ix];
426 cs_tprg = &this_program.ctrs[t_ix];
427 cs_all = &all.ctrs[t_ix];
429 if ((1 << t_ix) & gi_ptr->ctr_mask)
431 if (!cs_obj->runs++)
432 cs_obj->num = cs_tobj->num;
433 else if (cs_obj->num != cs_tobj->num)
434 goto read_mismatch;
435 cs_obj->sum_all += cs_tobj->sum_all;
436 if (cs_obj->run_max < cs_tobj->run_max)
437 cs_obj->run_max = cs_tobj->run_max;
438 cs_obj->sum_max += cs_tobj->run_max;
440 if (!cs_prg->runs++)
441 cs_prg->num = cs_tprg->num;
442 else if (cs_prg->num != cs_tprg->num)
443 goto read_mismatch;
444 cs_prg->sum_all += cs_tprg->sum_all;
445 if (cs_prg->run_max < cs_tprg->run_max)
446 cs_prg->run_max = cs_tprg->run_max;
447 cs_prg->sum_max += cs_tprg->run_max;
449 else if (cs_obj->num || cs_prg->num)
450 goto read_mismatch;
452 if (!cs_all->runs && cs_prg->runs)
453 memcpy (cs_all, cs_prg, sizeof (*cs_all));
454 else if (!all.checksum
455 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
456 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
458 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
459 gi_filename, GCOV_LOCKED
460 ? "" : " or concurrent update without locking support");
461 all.checksum = ~0u;
465 c_ix = 0;
466 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
467 if ((1 << t_ix) & gi_ptr->ctr_mask)
469 values[c_ix] = gi_ptr->counts[c_ix].values;
470 c_ix++;
473 program.checksum = gcov_crc32;
475 /* Write out the data. */
476 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
477 gcov_write_unsigned (gi_ptr->stamp);
479 /* Write execution counts for each function. */
480 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
482 fi_ptr = (const struct gcov_fn_info *)
483 ((const char *) gi_ptr->functions + f_ix * fi_stride);
485 /* Announce function. */
486 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
487 gcov_write_unsigned (fi_ptr->ident);
488 gcov_write_unsigned (fi_ptr->checksum);
490 c_ix = 0;
491 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
493 gcov_type *c_ptr;
495 if (!((1 << t_ix) & gi_ptr->ctr_mask))
496 continue;
498 n_counts = fi_ptr->n_ctrs[c_ix];
500 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
501 GCOV_TAG_COUNTER_LENGTH (n_counts));
502 c_ptr = values[c_ix];
503 while (n_counts--)
504 gcov_write_counter (*c_ptr++);
506 values[c_ix] = c_ptr;
507 c_ix++;
511 /* Object file summary. */
512 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
514 /* Generate whole program statistics. */
515 if (eof_pos)
516 gcov_seek (eof_pos);
517 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
518 if (!summary_pos)
519 gcov_write_unsigned (0);
520 if ((error = gcov_close ()))
521 fprintf (stderr, error < 0 ?
522 "profiling:%s:Overflow writing\n" :
523 "profiling:%s:Error writing\n",
524 gi_filename);
528 /* Add a new object file onto the bb chain. Invoked automatically
529 when running an object file's global ctors. */
531 void
532 __gcov_init (struct gcov_info *info)
534 if (!info->version)
535 return;
536 if (gcov_version (info, info->version, 0))
538 const char *ptr = info->filename;
539 gcov_unsigned_t crc32 = gcov_crc32;
540 size_t filename_length = strlen(info->filename);
542 /* Refresh the longest file name information */
543 if (filename_length > gcov_max_filename)
544 gcov_max_filename = filename_length;
548 unsigned ix;
549 gcov_unsigned_t value = *ptr << 24;
551 for (ix = 8; ix--; value <<= 1)
553 gcov_unsigned_t feedback;
555 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
556 crc32 <<= 1;
557 crc32 ^= feedback;
560 while (*ptr++);
562 gcov_crc32 = crc32;
564 if (!gcov_list)
565 atexit (gcov_exit);
567 info->next = gcov_list;
568 gcov_list = info;
570 info->version = 0;
573 /* Called before fork or exec - write out profile information gathered so
574 far and reset it to zero. This avoids duplication or loss of the
575 profile information gathered so far. */
577 void
578 __gcov_flush (void)
580 const struct gcov_info *gi_ptr;
582 gcov_exit ();
583 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
585 unsigned t_ix;
586 const struct gcov_ctr_info *ci_ptr;
588 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
589 if ((1 << t_ix) & gi_ptr->ctr_mask)
591 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
592 ci_ptr++;
597 #endif /* L_gcov */
599 #ifdef L_gcov_merge_add
600 /* The profile merging function that just adds the counters. It is given
601 an array COUNTERS of N_COUNTERS old counters and it reads the same number
602 of counters from the gcov file. */
603 void
604 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
606 for (; n_counters; counters++, n_counters--)
607 *counters += gcov_read_counter ();
609 #endif /* L_gcov_merge_add */
611 #ifdef L_gcov_merge_single
612 /* The profile merging function for choosing the most common value.
613 It is given an array COUNTERS of N_COUNTERS old counters and it
614 reads the same number of counters from the gcov file. The counters
615 are split into 3-tuples where the members of the tuple have
616 meanings:
618 -- the stored candidate on the most common value of the measured entity
619 -- counter
620 -- total number of evaluations of the value */
621 void
622 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
624 unsigned i, n_measures;
625 gcov_type value, counter, all;
627 gcc_assert (!(n_counters % 3));
628 n_measures = n_counters / 3;
629 for (i = 0; i < n_measures; i++, counters += 3)
631 value = gcov_read_counter ();
632 counter = gcov_read_counter ();
633 all = gcov_read_counter ();
635 if (counters[0] == value)
636 counters[1] += counter;
637 else if (counter > counters[1])
639 counters[0] = value;
640 counters[1] = counter - counters[1];
642 else
643 counters[1] -= counter;
644 counters[2] += all;
647 #endif /* L_gcov_merge_single */
649 #ifdef L_gcov_merge_delta
650 /* The profile merging function for choosing the most common
651 difference between two consecutive evaluations of the value. It is
652 given an array COUNTERS of N_COUNTERS old counters and it reads the
653 same number of counters from the gcov file. The counters are split
654 into 4-tuples where the members of the tuple have meanings:
656 -- the last value of the measured entity
657 -- the stored candidate on the most common difference
658 -- counter
659 -- total number of evaluations of the value */
660 void
661 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
663 unsigned i, n_measures;
664 gcov_type last, value, counter, all;
666 gcc_assert (!(n_counters % 4));
667 n_measures = n_counters / 4;
668 for (i = 0; i < n_measures; i++, counters += 4)
670 last = gcov_read_counter ();
671 value = gcov_read_counter ();
672 counter = gcov_read_counter ();
673 all = gcov_read_counter ();
675 if (counters[1] == value)
676 counters[2] += counter;
677 else if (counter > counters[2])
679 counters[1] = value;
680 counters[2] = counter - counters[2];
682 else
683 counters[2] -= counter;
684 counters[3] += all;
687 #endif /* L_gcov_merge_delta */
689 #ifdef L_gcov_interval_profiler
690 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
691 corresponding counter in COUNTERS. If the VALUE is above or below
692 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
693 instead. */
695 void
696 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
697 int start, unsigned steps)
699 gcov_type delta = value - start;
700 if (delta < 0)
701 counters[steps + 1]++;
702 else if (delta >= steps)
703 counters[steps]++;
704 else
705 counters[delta]++;
707 #endif
709 #ifdef L_gcov_pow2_profiler
710 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
711 COUNTERS[0] is incremented. */
713 void
714 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
716 if (value & (value - 1))
717 counters[0]++;
718 else
719 counters[1]++;
721 #endif
723 #ifdef L_gcov_one_value_profiler
724 /* Tries to determine the most common value among its inputs. Checks if the
725 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
726 is incremented. If this is not the case and COUNTERS[1] is not zero,
727 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
728 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
729 function is called more than 50% of the time with one value, this value
730 will be in COUNTERS[0] in the end.
732 In any case, COUNTERS[2] is incremented. */
734 void
735 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
737 if (value == counters[0])
738 counters[1]++;
739 else if (counters[1] == 0)
741 counters[1] = 1;
742 counters[0] = value;
744 else
745 counters[1]--;
746 counters[2]++;
748 #endif
750 #ifdef L_gcov_fork
751 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
752 that they are not counted twice. */
754 pid_t
755 __gcov_fork (void)
757 __gcov_flush ();
758 return fork ();
760 #endif
762 #ifdef L_gcov_execl
763 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
764 that they are not lost. */
767 __gcov_execl (const char *path, const char *arg, ...)
769 va_list ap, aq;
770 unsigned i, length;
771 char **args;
773 __gcov_flush ();
775 va_start (ap, arg);
776 va_copy (aq, ap);
778 length = 2;
779 while (va_arg (ap, char *))
780 length++;
781 va_end (ap);
783 args = alloca (length * sizeof (void *));
784 args[0] = (char *) arg;
785 for (i = 1; i < length; i++)
786 args[i] = va_arg (aq, char *);
787 va_end (aq);
789 return execv (path, args);
791 #endif
793 #ifdef L_gcov_execlp
794 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so
795 that they are not lost. */
798 __gcov_execlp (const char *path, const char *arg, ...)
800 va_list ap, aq;
801 unsigned i, length;
802 char **args;
804 __gcov_flush ();
806 va_start (ap, arg);
807 va_copy (aq, ap);
809 length = 2;
810 while (va_arg (ap, char *))
811 length++;
812 va_end (ap);
814 args = alloca (length * sizeof (void *));
815 args[0] = (char *) arg;
816 for (i = 1; i < length; i++)
817 args[i] = va_arg (aq, char *);
818 va_end (aq);
820 return execvp (path, args);
822 #endif
824 #ifdef L_gcov_execle
825 /* A wrapper for the execle function. Flushes the accumulated profiling data, so
826 that they are not lost. */
829 __gcov_execle (const char *path, const char *arg, ...)
831 va_list ap, aq;
832 unsigned i, length;
833 char **args;
834 char **envp;
836 __gcov_flush ();
838 va_start (ap, arg);
839 va_copy (aq, ap);
841 length = 2;
842 while (va_arg (ap, char *))
843 length++;
844 va_end (ap);
846 args = alloca (length * sizeof (void *));
847 args[0] = (char *) arg;
848 for (i = 1; i < length; i++)
849 args[i] = va_arg (aq, char *);
850 envp = va_arg (aq, char **);
851 va_end (aq);
853 return execve (path, args, envp);
855 #endif
857 #ifdef L_gcov_execv
858 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
859 that they are not lost. */
862 __gcov_execv (const char *path, char *const argv[])
864 __gcov_flush ();
865 return execv (path, argv);
867 #endif
869 #ifdef L_gcov_execvp
870 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so
871 that they are not lost. */
874 __gcov_execvp (const char *path, char *const argv[])
876 __gcov_flush ();
877 return execvp (path, argv);
879 #endif
881 #ifdef L_gcov_execve
882 /* A wrapper for the execve function. Flushes the accumulated profiling data, so
883 that they are not lost. */
886 __gcov_execve (const char *path, char *const argv[], char *const envp[])
888 __gcov_flush ();
889 return execve (path, argv, envp);
891 #endif
892 #endif /* inhibit_libc */