2005-06-30 J. D. Johnston <jjohnst@us.ibm.com>
[official-gcc.git] / gcc / libgcov.c
blob09f3522537a7413c1157d8234c640a4778ff14a5
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, 51 Franklin Street, Fifth Floor, Boston, MA
30 02110-1301, 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 component 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 unnecessary trailing '/' */
212 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
213 prefix_length--;
215 else
216 prefix_length = 0;
218 /* Allocate and initialize the filename scratch space. */
219 gi_filename = alloca (prefix_length + gcov_max_filename + 1);
220 if (prefix_length)
221 memcpy (gi_filename, gcov_prefix, prefix_length);
222 gi_filename_up = gi_filename + prefix_length;
224 /* Now merge each file. */
225 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
227 struct gcov_summary this_object;
228 struct gcov_summary object, program;
229 gcov_type *values[GCOV_COUNTERS];
230 const struct gcov_fn_info *fi_ptr;
231 unsigned fi_stride;
232 unsigned c_ix, f_ix, n_counts;
233 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
234 int error = 0;
235 gcov_unsigned_t tag, length;
236 gcov_position_t summary_pos = 0;
237 gcov_position_t eof_pos = 0;
239 memset (&this_object, 0, sizeof (this_object));
240 memset (&object, 0, sizeof (object));
242 /* Build relocated filename, stripping off leading
243 directories from the initial filename if requested. */
244 if (gcov_prefix_strip > 0)
246 int level = 0;
247 const char *fname = gi_ptr->filename;
248 const char *s;
250 /* Skip selected directory levels. */
251 for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
252 if (IS_DIR_SEPARATOR(*s))
254 fname = s;
255 level++;
258 /* Update complete filename with stripped original. */
259 strcpy (gi_filename_up, fname);
261 else
262 strcpy (gi_filename_up, gi_ptr->filename);
264 /* Totals for this object file. */
265 ci_ptr = gi_ptr->counts;
266 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
268 if (!((1 << t_ix) & gi_ptr->ctr_mask))
269 continue;
271 cs_ptr = &this_object.ctrs[t_ix];
272 cs_ptr->num += ci_ptr->num;
273 for (c_num = 0; c_num < ci_ptr->num; c_num++)
275 cs_ptr->sum_all += ci_ptr->values[c_num];
276 if (cs_ptr->run_max < ci_ptr->values[c_num])
277 cs_ptr->run_max = ci_ptr->values[c_num];
280 ci_ptr++;
283 c_ix = 0;
284 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
285 if ((1 << t_ix) & gi_ptr->ctr_mask)
287 values[c_ix] = gi_ptr->counts[c_ix].values;
288 c_ix++;
291 /* Calculate the function_info stride. This depends on the
292 number of counter types being measured. */
293 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
294 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
296 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
297 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
300 if (!gcov_open (gi_filename))
302 /* Open failed likely due to missed directory.
303 Create directory and retry to open file. */
304 if (create_file_directory (gi_filename))
306 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
307 continue;
309 if (!gcov_open (gi_filename))
311 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
312 continue;
316 tag = gcov_read_unsigned ();
317 if (tag)
319 /* Merge data from file. */
320 if (tag != GCOV_DATA_MAGIC)
322 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
323 gi_filename);
324 goto read_fatal;
326 length = gcov_read_unsigned ();
327 if (!gcov_version (gi_ptr, length, gi_filename))
328 goto read_fatal;
330 length = gcov_read_unsigned ();
331 if (length != gi_ptr->stamp)
332 /* Read from a different compilation. Overwrite the file. */
333 goto rewrite;
335 /* Merge execution counts for each function. */
336 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
338 fi_ptr = (const struct gcov_fn_info *)
339 ((const char *) gi_ptr->functions + f_ix * fi_stride);
340 tag = gcov_read_unsigned ();
341 length = gcov_read_unsigned ();
343 /* Check function. */
344 if (tag != GCOV_TAG_FUNCTION
345 || length != GCOV_TAG_FUNCTION_LENGTH
346 || gcov_read_unsigned () != fi_ptr->ident
347 || gcov_read_unsigned () != fi_ptr->checksum)
349 read_mismatch:;
350 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
351 gi_filename,
352 f_ix + 1 ? "function" : "summaries");
353 goto read_fatal;
356 c_ix = 0;
357 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
359 gcov_merge_fn merge;
361 if (!((1 << t_ix) & gi_ptr->ctr_mask))
362 continue;
364 n_counts = fi_ptr->n_ctrs[c_ix];
365 merge = gi_ptr->counts[c_ix].merge;
367 tag = gcov_read_unsigned ();
368 length = gcov_read_unsigned ();
369 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
370 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
371 goto read_mismatch;
372 (*merge) (values[c_ix], n_counts);
373 values[c_ix] += n_counts;
374 c_ix++;
376 if ((error = gcov_is_error ()))
377 goto read_error;
380 f_ix = ~0u;
381 /* Check program & object summary */
382 while (1)
384 int is_program;
386 eof_pos = gcov_position ();
387 tag = gcov_read_unsigned ();
388 if (!tag)
389 break;
391 length = gcov_read_unsigned ();
392 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
393 if (length != GCOV_TAG_SUMMARY_LENGTH
394 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
395 goto read_mismatch;
396 gcov_read_summary (is_program ? &program : &object);
397 if ((error = gcov_is_error ()))
398 goto read_error;
399 if (is_program && program.checksum == gcov_crc32)
401 summary_pos = eof_pos;
402 goto rewrite;
406 goto rewrite;
408 read_error:;
409 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
410 : "profiling:%s:Error merging\n", gi_filename);
412 read_fatal:;
413 gcov_close ();
414 continue;
416 rewrite:;
417 gcov_rewrite ();
418 if (!summary_pos)
419 memset (&program, 0, sizeof (program));
421 /* Merge the summaries. */
422 f_ix = ~0u;
423 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
425 cs_obj = &object.ctrs[t_ix];
426 cs_tobj = &this_object.ctrs[t_ix];
427 cs_prg = &program.ctrs[t_ix];
428 cs_tprg = &this_program.ctrs[t_ix];
429 cs_all = &all.ctrs[t_ix];
431 if ((1 << t_ix) & gi_ptr->ctr_mask)
433 if (!cs_obj->runs++)
434 cs_obj->num = cs_tobj->num;
435 else if (cs_obj->num != cs_tobj->num)
436 goto read_mismatch;
437 cs_obj->sum_all += cs_tobj->sum_all;
438 if (cs_obj->run_max < cs_tobj->run_max)
439 cs_obj->run_max = cs_tobj->run_max;
440 cs_obj->sum_max += cs_tobj->run_max;
442 if (!cs_prg->runs++)
443 cs_prg->num = cs_tprg->num;
444 else if (cs_prg->num != cs_tprg->num)
445 goto read_mismatch;
446 cs_prg->sum_all += cs_tprg->sum_all;
447 if (cs_prg->run_max < cs_tprg->run_max)
448 cs_prg->run_max = cs_tprg->run_max;
449 cs_prg->sum_max += cs_tprg->run_max;
451 else if (cs_obj->num || cs_prg->num)
452 goto read_mismatch;
454 if (!cs_all->runs && cs_prg->runs)
455 memcpy (cs_all, cs_prg, sizeof (*cs_all));
456 else if (!all.checksum
457 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
458 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
460 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
461 gi_filename, GCOV_LOCKED
462 ? "" : " or concurrent update without locking support");
463 all.checksum = ~0u;
467 c_ix = 0;
468 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
469 if ((1 << t_ix) & gi_ptr->ctr_mask)
471 values[c_ix] = gi_ptr->counts[c_ix].values;
472 c_ix++;
475 program.checksum = gcov_crc32;
477 /* Write out the data. */
478 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
479 gcov_write_unsigned (gi_ptr->stamp);
481 /* Write execution counts for each function. */
482 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
484 fi_ptr = (const struct gcov_fn_info *)
485 ((const char *) gi_ptr->functions + f_ix * fi_stride);
487 /* Announce function. */
488 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
489 gcov_write_unsigned (fi_ptr->ident);
490 gcov_write_unsigned (fi_ptr->checksum);
492 c_ix = 0;
493 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
495 gcov_type *c_ptr;
497 if (!((1 << t_ix) & gi_ptr->ctr_mask))
498 continue;
500 n_counts = fi_ptr->n_ctrs[c_ix];
502 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
503 GCOV_TAG_COUNTER_LENGTH (n_counts));
504 c_ptr = values[c_ix];
505 while (n_counts--)
506 gcov_write_counter (*c_ptr++);
508 values[c_ix] = c_ptr;
509 c_ix++;
513 /* Object file summary. */
514 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
516 /* Generate whole program statistics. */
517 if (eof_pos)
518 gcov_seek (eof_pos);
519 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
520 if (!summary_pos)
521 gcov_write_unsigned (0);
522 if ((error = gcov_close ()))
523 fprintf (stderr, error < 0 ?
524 "profiling:%s:Overflow writing\n" :
525 "profiling:%s:Error writing\n",
526 gi_filename);
530 /* Add a new object file onto the bb chain. Invoked automatically
531 when running an object file's global ctors. */
533 void
534 __gcov_init (struct gcov_info *info)
536 if (!info->version)
537 return;
538 if (gcov_version (info, info->version, 0))
540 const char *ptr = info->filename;
541 gcov_unsigned_t crc32 = gcov_crc32;
542 size_t filename_length = strlen(info->filename);
544 /* Refresh the longest file name information */
545 if (filename_length > gcov_max_filename)
546 gcov_max_filename = filename_length;
550 unsigned ix;
551 gcov_unsigned_t value = *ptr << 24;
553 for (ix = 8; ix--; value <<= 1)
555 gcov_unsigned_t feedback;
557 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
558 crc32 <<= 1;
559 crc32 ^= feedback;
562 while (*ptr++);
564 gcov_crc32 = crc32;
566 if (!gcov_list)
567 atexit (gcov_exit);
569 info->next = gcov_list;
570 gcov_list = info;
572 info->version = 0;
575 /* Called before fork or exec - write out profile information gathered so
576 far and reset it to zero. This avoids duplication or loss of the
577 profile information gathered so far. */
579 void
580 __gcov_flush (void)
582 const struct gcov_info *gi_ptr;
584 gcov_exit ();
585 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
587 unsigned t_ix;
588 const struct gcov_ctr_info *ci_ptr;
590 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
591 if ((1 << t_ix) & gi_ptr->ctr_mask)
593 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
594 ci_ptr++;
599 #endif /* L_gcov */
601 #ifdef L_gcov_merge_add
602 /* The profile merging function that just adds the counters. It is given
603 an array COUNTERS of N_COUNTERS old counters and it reads the same number
604 of counters from the gcov file. */
605 void
606 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
608 for (; n_counters; counters++, n_counters--)
609 *counters += gcov_read_counter ();
611 #endif /* L_gcov_merge_add */
613 #ifdef L_gcov_merge_single
614 /* The profile merging function for choosing the most common value.
615 It is given an array COUNTERS of N_COUNTERS old counters and it
616 reads the same number of counters from the gcov file. The counters
617 are split into 3-tuples where the members of the tuple have
618 meanings:
620 -- the stored candidate on the most common value of the measured entity
621 -- counter
622 -- total number of evaluations of the value */
623 void
624 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
626 unsigned i, n_measures;
627 gcov_type value, counter, all;
629 gcc_assert (!(n_counters % 3));
630 n_measures = n_counters / 3;
631 for (i = 0; i < n_measures; i++, counters += 3)
633 value = gcov_read_counter ();
634 counter = gcov_read_counter ();
635 all = gcov_read_counter ();
637 if (counters[0] == value)
638 counters[1] += counter;
639 else if (counter > counters[1])
641 counters[0] = value;
642 counters[1] = counter - counters[1];
644 else
645 counters[1] -= counter;
646 counters[2] += all;
649 #endif /* L_gcov_merge_single */
651 #ifdef L_gcov_merge_delta
652 /* The profile merging function for choosing the most common
653 difference between two consecutive evaluations of the value. It is
654 given an array COUNTERS of N_COUNTERS old counters and it reads the
655 same number of counters from the gcov file. The counters are split
656 into 4-tuples where the members of the tuple have meanings:
658 -- the last value of the measured entity
659 -- the stored candidate on the most common difference
660 -- counter
661 -- total number of evaluations of the value */
662 void
663 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
665 unsigned i, n_measures;
666 gcov_type last, value, counter, all;
668 gcc_assert (!(n_counters % 4));
669 n_measures = n_counters / 4;
670 for (i = 0; i < n_measures; i++, counters += 4)
672 last = gcov_read_counter ();
673 value = gcov_read_counter ();
674 counter = gcov_read_counter ();
675 all = gcov_read_counter ();
677 if (counters[1] == value)
678 counters[2] += counter;
679 else if (counter > counters[2])
681 counters[1] = value;
682 counters[2] = counter - counters[2];
684 else
685 counters[2] -= counter;
686 counters[3] += all;
689 #endif /* L_gcov_merge_delta */
691 #ifdef L_gcov_interval_profiler
692 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
693 corresponding counter in COUNTERS. If the VALUE is above or below
694 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
695 instead. */
697 void
698 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
699 int start, unsigned steps)
701 gcov_type delta = value - start;
702 if (delta < 0)
703 counters[steps + 1]++;
704 else if (delta >= steps)
705 counters[steps]++;
706 else
707 counters[delta]++;
709 #endif
711 #ifdef L_gcov_pow2_profiler
712 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
713 COUNTERS[0] is incremented. */
715 void
716 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
718 if (value & (value - 1))
719 counters[0]++;
720 else
721 counters[1]++;
723 #endif
725 #ifdef L_gcov_one_value_profiler
726 /* Tries to determine the most common value among its inputs. Checks if the
727 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
728 is incremented. If this is not the case and COUNTERS[1] is not zero,
729 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
730 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
731 function is called more than 50% of the time with one value, this value
732 will be in COUNTERS[0] in the end.
734 In any case, COUNTERS[2] is incremented. */
736 void
737 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
739 if (value == counters[0])
740 counters[1]++;
741 else if (counters[1] == 0)
743 counters[1] = 1;
744 counters[0] = value;
746 else
747 counters[1]--;
748 counters[2]++;
750 #endif
752 #ifdef L_gcov_fork
753 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
754 that they are not counted twice. */
756 pid_t
757 __gcov_fork (void)
759 __gcov_flush ();
760 return fork ();
762 #endif
764 #ifdef L_gcov_execl
765 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
766 that they are not lost. */
769 __gcov_execl (const char *path, const char *arg, ...)
771 va_list ap, aq;
772 unsigned i, length;
773 char **args;
775 __gcov_flush ();
777 va_start (ap, arg);
778 va_copy (aq, ap);
780 length = 2;
781 while (va_arg (ap, char *))
782 length++;
783 va_end (ap);
785 args = alloca (length * sizeof (void *));
786 args[0] = (char *) arg;
787 for (i = 1; i < length; i++)
788 args[i] = va_arg (aq, char *);
789 va_end (aq);
791 return execv (path, args);
793 #endif
795 #ifdef L_gcov_execlp
796 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so
797 that they are not lost. */
800 __gcov_execlp (const char *path, const char *arg, ...)
802 va_list ap, aq;
803 unsigned i, length;
804 char **args;
806 __gcov_flush ();
808 va_start (ap, arg);
809 va_copy (aq, ap);
811 length = 2;
812 while (va_arg (ap, char *))
813 length++;
814 va_end (ap);
816 args = alloca (length * sizeof (void *));
817 args[0] = (char *) arg;
818 for (i = 1; i < length; i++)
819 args[i] = va_arg (aq, char *);
820 va_end (aq);
822 return execvp (path, args);
824 #endif
826 #ifdef L_gcov_execle
827 /* A wrapper for the execle function. Flushes the accumulated profiling data, so
828 that they are not lost. */
831 __gcov_execle (const char *path, const char *arg, ...)
833 va_list ap, aq;
834 unsigned i, length;
835 char **args;
836 char **envp;
838 __gcov_flush ();
840 va_start (ap, arg);
841 va_copy (aq, ap);
843 length = 2;
844 while (va_arg (ap, char *))
845 length++;
846 va_end (ap);
848 args = alloca (length * sizeof (void *));
849 args[0] = (char *) arg;
850 for (i = 1; i < length; i++)
851 args[i] = va_arg (aq, char *);
852 envp = va_arg (aq, char **);
853 va_end (aq);
855 return execve (path, args, envp);
857 #endif
859 #ifdef L_gcov_execv
860 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
861 that they are not lost. */
864 __gcov_execv (const char *path, char *const argv[])
866 __gcov_flush ();
867 return execv (path, argv);
869 #endif
871 #ifdef L_gcov_execvp
872 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so
873 that they are not lost. */
876 __gcov_execvp (const char *path, char *const argv[])
878 __gcov_flush ();
879 return execvp (path, argv);
881 #endif
883 #ifdef L_gcov_execve
884 /* A wrapper for the execve function. Flushes the accumulated profiling data, so
885 that they are not lost. */
888 __gcov_execve (const char *path, char *const argv[], char *const envp[])
890 __gcov_flush ();
891 return execve (path, argv, envp);
893 #endif
894 #endif /* inhibit_libc */