2011-04-29 Tobias Burnus <burnus@net-b.de>
[official-gcc.git] / gcc / libgcov.c
blob7d1f6d052900f96d251865f180f52738d8292e1a
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, 2008, 2009, 2010
5 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
12 version.
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
19 Under Section 7 of GPL version 3, you are granted additional
20 permissions described in the GCC Runtime Library Exception, version
21 3.1, as published by the Free Software Foundation.
23 You should have received a copy of the GNU General Public License and
24 a copy of the GCC Runtime Library Exception along with this program;
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26 <http://www.gnu.org/licenses/>. */
28 #include "tconfig.h"
29 #include "tsystem.h"
30 #include "coretypes.h"
31 #include "tm.h"
33 #if defined(inhibit_libc)
34 #define IN_LIBGCOV (-1)
35 #else
36 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
37 #include <stdio.h>
38 #define IN_LIBGCOV 1
39 #if defined(L_gcov)
40 #define GCOV_LINKAGE /* nothing */
41 #endif
42 #endif
43 #include "gcov-io.h"
45 #if defined(inhibit_libc)
46 /* If libc and its header files are not available, provide dummy functions. */
48 #ifdef L_gcov
49 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
50 void __gcov_flush (void) {}
51 #endif
53 #ifdef L_gcov_merge_add
54 void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
55 unsigned n_counters __attribute__ ((unused))) {}
56 #endif
58 #ifdef L_gcov_merge_single
59 void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
60 unsigned n_counters __attribute__ ((unused))) {}
61 #endif
63 #ifdef L_gcov_merge_delta
64 void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
65 unsigned n_counters __attribute__ ((unused))) {}
66 #endif
68 #else
70 #include <string.h>
71 #if GCOV_LOCKED
72 #include <fcntl.h>
73 #include <errno.h>
74 #include <sys/stat.h>
75 #endif
77 #ifdef L_gcov
78 #include "gcov-io.c"
80 /* Chain of per-object gcov structures. */
81 static struct gcov_info *gcov_list;
83 /* A program checksum allows us to distinguish program data for an
84 object file included in multiple programs. */
85 static gcov_unsigned_t gcov_crc32;
87 /* Size of the longest file name. */
88 static size_t gcov_max_filename = 0;
90 /* Make sure path component of the given FILENAME exists, create
91 missing directories. FILENAME must be writable.
92 Returns zero on success, or -1 if an error occurred. */
94 static int
95 create_file_directory (char *filename)
97 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
98 (void) filename;
99 return -1;
100 #else
101 char *s;
103 s = filename;
105 if (HAS_DRIVE_SPEC(s))
106 s += 2;
107 if (IS_DIR_SEPARATOR(*s))
108 ++s;
109 for (; *s != '\0'; s++)
110 if (IS_DIR_SEPARATOR(*s))
112 char sep = *s;
113 *s = '\0';
115 /* Try to make directory if it doesn't already exist. */
116 if (access (filename, F_OK) == -1
117 #ifdef TARGET_POSIX_IO
118 && mkdir (filename, 0755) == -1
119 #else
120 && mkdir (filename) == -1
121 #endif
122 /* The directory might have been made by another process. */
123 && errno != EEXIST)
125 fprintf (stderr, "profiling:%s:Cannot create directory\n",
126 filename);
127 *s = sep;
128 return -1;
131 *s = sep;
133 return 0;
134 #endif
137 /* Check if VERSION of the info block PTR matches libgcov one.
138 Return 1 on success, or zero in case of versions mismatch.
139 If FILENAME is not NULL, its value used for reporting purposes
140 instead of value from the info block. */
142 static int
143 gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
144 const char *filename)
146 if (version != GCOV_VERSION)
148 char v[4], e[4];
150 GCOV_UNSIGNED2STRING (v, version);
151 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
153 fprintf (stderr,
154 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
155 filename? filename : ptr->filename, e, v);
156 return 0;
158 return 1;
161 /* Dump the coverage counts. We merge with existing counts when
162 possible, to avoid growing the .da files ad infinitum. We use this
163 program's checksum to make sure we only accumulate whole program
164 statistics to the correct summary. An object file might be embedded
165 in two separate programs, and we must keep the two program
166 summaries separate. */
168 static void
169 gcov_exit (void)
171 struct gcov_info *gi_ptr;
172 struct gcov_summary this_program;
173 struct gcov_summary all;
174 struct gcov_ctr_summary *cs_ptr;
175 const struct gcov_ctr_info *ci_ptr;
176 unsigned t_ix;
177 gcov_unsigned_t c_num;
178 const char *gcov_prefix;
179 int gcov_prefix_strip = 0;
180 size_t prefix_length;
181 char *gi_filename, *gi_filename_up;
183 memset (&all, 0, sizeof (all));
184 /* Find the totals for this execution. */
185 memset (&this_program, 0, sizeof (this_program));
186 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
188 ci_ptr = gi_ptr->counts;
189 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
191 if (!((1 << t_ix) & gi_ptr->ctr_mask))
192 continue;
194 cs_ptr = &this_program.ctrs[t_ix];
195 cs_ptr->num += ci_ptr->num;
196 for (c_num = 0; c_num < ci_ptr->num; c_num++)
198 cs_ptr->sum_all += ci_ptr->values[c_num];
199 if (cs_ptr->run_max < ci_ptr->values[c_num])
200 cs_ptr->run_max = ci_ptr->values[c_num];
202 ci_ptr++;
207 /* Check if the level of dirs to strip off specified. */
208 char *tmp = getenv("GCOV_PREFIX_STRIP");
209 if (tmp)
211 gcov_prefix_strip = atoi (tmp);
212 /* Do not consider negative values. */
213 if (gcov_prefix_strip < 0)
214 gcov_prefix_strip = 0;
217 /* Get file name relocation prefix. Non-absolute values are ignored. */
218 gcov_prefix = getenv("GCOV_PREFIX");
219 if (gcov_prefix)
221 prefix_length = strlen(gcov_prefix);
223 /* Remove an unnecessary trailing '/' */
224 if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
225 prefix_length--;
227 else
228 prefix_length = 0;
230 /* If no prefix was specified and a prefix stip, then we assume
231 relative. */
232 if (gcov_prefix_strip != 0 && prefix_length == 0)
234 gcov_prefix = ".";
235 prefix_length = 1;
237 /* Allocate and initialize the filename scratch space plus one. */
238 gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 2);
239 if (prefix_length)
240 memcpy (gi_filename, gcov_prefix, prefix_length);
241 gi_filename_up = gi_filename + prefix_length;
243 /* Now merge each file. */
244 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
246 struct gcov_summary this_object;
247 struct gcov_summary object, program;
248 gcov_type *values[GCOV_COUNTERS];
249 const struct gcov_fn_info *fi_ptr;
250 unsigned fi_stride;
251 unsigned c_ix, f_ix, n_counts;
252 struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
253 int error = 0;
254 gcov_unsigned_t tag, length;
255 gcov_position_t summary_pos = 0;
256 gcov_position_t eof_pos = 0;
257 const char *fname, *s;
259 fname = gi_ptr->filename;
261 memset (&this_object, 0, sizeof (this_object));
262 memset (&object, 0, sizeof (object));
264 /* Avoid to add multiple drive letters into combined path. */
265 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
266 fname += 2;
268 /* Build relocated filename, stripping off leading
269 directories from the initial filename if requested. */
270 if (gcov_prefix_strip > 0)
272 int level = 0;
273 s = fname;
274 if (IS_DIR_SEPARATOR(*s))
275 ++s;
277 /* Skip selected directory levels. */
278 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
279 if (IS_DIR_SEPARATOR(*s))
281 fname = s;
282 level++;
285 /* Update complete filename with stripped original. */
286 if (!IS_DIR_SEPARATOR (*fname) && !HAS_DRIVE_SPEC(fname))
288 strcpy (gi_filename_up, "/");
289 strcpy (gi_filename_up + 1, fname);
291 else
292 strcpy (gi_filename_up, fname);
294 /* Totals for this object file. */
295 ci_ptr = gi_ptr->counts;
296 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
298 if (!((1 << t_ix) & gi_ptr->ctr_mask))
299 continue;
301 cs_ptr = &this_object.ctrs[t_ix];
302 cs_ptr->num += ci_ptr->num;
303 for (c_num = 0; c_num < ci_ptr->num; c_num++)
305 cs_ptr->sum_all += ci_ptr->values[c_num];
306 if (cs_ptr->run_max < ci_ptr->values[c_num])
307 cs_ptr->run_max = ci_ptr->values[c_num];
310 ci_ptr++;
313 c_ix = 0;
314 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
315 if ((1 << t_ix) & gi_ptr->ctr_mask)
317 values[c_ix] = gi_ptr->counts[c_ix].values;
318 c_ix++;
321 /* Calculate the function_info stride. This depends on the
322 number of counter types being measured. */
323 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
324 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
326 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
327 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
330 if (!gcov_open (gi_filename))
332 /* Open failed likely due to missed directory.
333 Create directory and retry to open file. */
334 if (create_file_directory (gi_filename))
336 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
337 continue;
339 if (!gcov_open (gi_filename))
341 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
342 continue;
346 tag = gcov_read_unsigned ();
347 if (tag)
349 /* Merge data from file. */
350 if (tag != GCOV_DATA_MAGIC)
352 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
353 gi_filename);
354 goto read_fatal;
356 length = gcov_read_unsigned ();
357 if (!gcov_version (gi_ptr, length, gi_filename))
358 goto read_fatal;
360 length = gcov_read_unsigned ();
361 if (length != gi_ptr->stamp)
362 /* Read from a different compilation. Overwrite the file. */
363 goto rewrite;
365 /* Merge execution counts for each function. */
366 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
368 fi_ptr = (const struct gcov_fn_info *)
369 ((const char *) gi_ptr->functions + f_ix * fi_stride);
370 tag = gcov_read_unsigned ();
371 length = gcov_read_unsigned ();
373 /* Check function. */
374 if (tag != GCOV_TAG_FUNCTION
375 || length != GCOV_TAG_FUNCTION_LENGTH
376 || gcov_read_unsigned () != fi_ptr->ident
377 || gcov_read_unsigned () != fi_ptr->lineno_checksum
378 || gcov_read_unsigned () != fi_ptr->cfg_checksum)
380 read_mismatch:;
381 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
382 gi_filename,
383 f_ix + 1 ? "function" : "summaries");
384 goto read_fatal;
387 c_ix = 0;
388 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
390 gcov_merge_fn merge;
392 if (!((1 << t_ix) & gi_ptr->ctr_mask))
393 continue;
395 n_counts = fi_ptr->n_ctrs[c_ix];
396 merge = gi_ptr->counts[c_ix].merge;
398 tag = gcov_read_unsigned ();
399 length = gcov_read_unsigned ();
400 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
401 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
402 goto read_mismatch;
403 (*merge) (values[c_ix], n_counts);
404 values[c_ix] += n_counts;
405 c_ix++;
407 if ((error = gcov_is_error ()))
408 goto read_error;
411 f_ix = ~0u;
412 /* Check program & object summary */
413 while (1)
415 int is_program;
417 eof_pos = gcov_position ();
418 tag = gcov_read_unsigned ();
419 if (!tag)
420 break;
422 length = gcov_read_unsigned ();
423 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
424 if (length != GCOV_TAG_SUMMARY_LENGTH
425 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
426 goto read_mismatch;
427 gcov_read_summary (is_program ? &program : &object);
428 if ((error = gcov_is_error ()))
429 goto read_error;
430 if (is_program && program.checksum == gcov_crc32)
432 summary_pos = eof_pos;
433 goto rewrite;
437 goto rewrite;
439 read_error:;
440 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
441 : "profiling:%s:Error merging\n", gi_filename);
443 read_fatal:;
444 gcov_close ();
445 continue;
447 rewrite:;
448 gcov_rewrite ();
449 if (!summary_pos)
450 memset (&program, 0, sizeof (program));
452 /* Merge the summaries. */
453 f_ix = ~0u;
454 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
456 cs_obj = &object.ctrs[t_ix];
457 cs_tobj = &this_object.ctrs[t_ix];
458 cs_prg = &program.ctrs[t_ix];
459 cs_tprg = &this_program.ctrs[t_ix];
460 cs_all = &all.ctrs[t_ix];
462 if ((1 << t_ix) & gi_ptr->ctr_mask)
464 if (!cs_obj->runs++)
465 cs_obj->num = cs_tobj->num;
466 else if (cs_obj->num != cs_tobj->num)
467 goto read_mismatch;
468 cs_obj->sum_all += cs_tobj->sum_all;
469 if (cs_obj->run_max < cs_tobj->run_max)
470 cs_obj->run_max = cs_tobj->run_max;
471 cs_obj->sum_max += cs_tobj->run_max;
473 if (!cs_prg->runs++)
474 cs_prg->num = cs_tprg->num;
475 else if (cs_prg->num != cs_tprg->num)
476 goto read_mismatch;
477 cs_prg->sum_all += cs_tprg->sum_all;
478 if (cs_prg->run_max < cs_tprg->run_max)
479 cs_prg->run_max = cs_tprg->run_max;
480 cs_prg->sum_max += cs_tprg->run_max;
482 else if (cs_obj->num || cs_prg->num)
483 goto read_mismatch;
485 if (!cs_all->runs && cs_prg->runs)
486 memcpy (cs_all, cs_prg, sizeof (*cs_all));
487 else if (!all.checksum
488 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
489 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
491 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
492 gi_filename, GCOV_LOCKED
493 ? "" : " or concurrent update without locking support");
494 all.checksum = ~0u;
498 c_ix = 0;
499 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
500 if ((1 << t_ix) & gi_ptr->ctr_mask)
502 values[c_ix] = gi_ptr->counts[c_ix].values;
503 c_ix++;
506 program.checksum = gcov_crc32;
508 /* Write out the data. */
509 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
510 gcov_write_unsigned (gi_ptr->stamp);
512 /* Write execution counts for each function. */
513 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
515 fi_ptr = (const struct gcov_fn_info *)
516 ((const char *) gi_ptr->functions + f_ix * fi_stride);
518 /* Announce function. */
519 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
520 gcov_write_unsigned (fi_ptr->ident);
521 gcov_write_unsigned (fi_ptr->lineno_checksum);
522 gcov_write_unsigned (fi_ptr->cfg_checksum);
524 c_ix = 0;
525 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
527 gcov_type *c_ptr;
529 if (!((1 << t_ix) & gi_ptr->ctr_mask))
530 continue;
532 n_counts = fi_ptr->n_ctrs[c_ix];
534 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
535 GCOV_TAG_COUNTER_LENGTH (n_counts));
536 c_ptr = values[c_ix];
537 while (n_counts--)
538 gcov_write_counter (*c_ptr++);
540 values[c_ix] = c_ptr;
541 c_ix++;
545 /* Object file summary. */
546 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
548 /* Generate whole program statistics. */
549 if (eof_pos)
550 gcov_seek (eof_pos);
551 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
552 if (!summary_pos)
553 gcov_write_unsigned (0);
554 if ((error = gcov_close ()))
555 fprintf (stderr, error < 0 ?
556 "profiling:%s:Overflow writing\n" :
557 "profiling:%s:Error writing\n",
558 gi_filename);
562 /* Add a new object file onto the bb chain. Invoked automatically
563 when running an object file's global ctors. */
565 void
566 __gcov_init (struct gcov_info *info)
568 if (!info->version)
569 return;
570 if (gcov_version (info, info->version, 0))
572 const char *ptr = info->filename;
573 gcov_unsigned_t crc32 = gcov_crc32;
574 size_t filename_length = strlen(info->filename);
576 /* Refresh the longest file name information */
577 if (filename_length > gcov_max_filename)
578 gcov_max_filename = filename_length;
582 unsigned ix;
583 gcov_unsigned_t value = *ptr << 24;
585 for (ix = 8; ix--; value <<= 1)
587 gcov_unsigned_t feedback;
589 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
590 crc32 <<= 1;
591 crc32 ^= feedback;
594 while (*ptr++);
596 gcov_crc32 = crc32;
598 if (!gcov_list)
599 atexit (gcov_exit);
601 info->next = gcov_list;
602 gcov_list = info;
604 info->version = 0;
607 /* Called before fork or exec - write out profile information gathered so
608 far and reset it to zero. This avoids duplication or loss of the
609 profile information gathered so far. */
611 void
612 __gcov_flush (void)
614 const struct gcov_info *gi_ptr;
616 gcov_exit ();
617 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
619 unsigned t_ix;
620 const struct gcov_ctr_info *ci_ptr;
622 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
623 if ((1 << t_ix) & gi_ptr->ctr_mask)
625 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
626 ci_ptr++;
631 #endif /* L_gcov */
633 #ifdef L_gcov_merge_add
634 /* The profile merging function that just adds the counters. It is given
635 an array COUNTERS of N_COUNTERS old counters and it reads the same number
636 of counters from the gcov file. */
637 void
638 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
640 for (; n_counters; counters++, n_counters--)
641 *counters += gcov_read_counter ();
643 #endif /* L_gcov_merge_add */
645 #ifdef L_gcov_merge_ior
646 /* The profile merging function that just adds the counters. It is given
647 an array COUNTERS of N_COUNTERS old counters and it reads the same number
648 of counters from the gcov file. */
649 void
650 __gcov_merge_ior (gcov_type *counters, unsigned n_counters)
652 for (; n_counters; counters++, n_counters--)
653 *counters |= gcov_read_counter ();
655 #endif
657 #ifdef L_gcov_merge_single
658 /* The profile merging function for choosing the most common value.
659 It is given an array COUNTERS of N_COUNTERS old counters and it
660 reads the same number of counters from the gcov file. The counters
661 are split into 3-tuples where the members of the tuple have
662 meanings:
664 -- the stored candidate on the most common value of the measured entity
665 -- counter
666 -- total number of evaluations of the value */
667 void
668 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
670 unsigned i, n_measures;
671 gcov_type value, counter, all;
673 gcc_assert (!(n_counters % 3));
674 n_measures = n_counters / 3;
675 for (i = 0; i < n_measures; i++, counters += 3)
677 value = gcov_read_counter ();
678 counter = gcov_read_counter ();
679 all = gcov_read_counter ();
681 if (counters[0] == value)
682 counters[1] += counter;
683 else if (counter > counters[1])
685 counters[0] = value;
686 counters[1] = counter - counters[1];
688 else
689 counters[1] -= counter;
690 counters[2] += all;
693 #endif /* L_gcov_merge_single */
695 #ifdef L_gcov_merge_delta
696 /* The profile merging function for choosing the most common
697 difference between two consecutive evaluations of the value. It is
698 given an array COUNTERS of N_COUNTERS old counters and it reads the
699 same number of counters from the gcov file. The counters are split
700 into 4-tuples where the members of the tuple have meanings:
702 -- the last value of the measured entity
703 -- the stored candidate on the most common difference
704 -- counter
705 -- total number of evaluations of the value */
706 void
707 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
709 unsigned i, n_measures;
710 gcov_type value, counter, all;
712 gcc_assert (!(n_counters % 4));
713 n_measures = n_counters / 4;
714 for (i = 0; i < n_measures; i++, counters += 4)
716 /* last = */ gcov_read_counter ();
717 value = gcov_read_counter ();
718 counter = gcov_read_counter ();
719 all = gcov_read_counter ();
721 if (counters[1] == value)
722 counters[2] += counter;
723 else if (counter > counters[2])
725 counters[1] = value;
726 counters[2] = counter - counters[2];
728 else
729 counters[2] -= counter;
730 counters[3] += all;
733 #endif /* L_gcov_merge_delta */
735 #ifdef L_gcov_interval_profiler
736 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
737 corresponding counter in COUNTERS. If the VALUE is above or below
738 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
739 instead. */
741 void
742 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
743 int start, unsigned steps)
745 gcov_type delta = value - start;
746 if (delta < 0)
747 counters[steps + 1]++;
748 else if (delta >= steps)
749 counters[steps]++;
750 else
751 counters[delta]++;
753 #endif
755 #ifdef L_gcov_pow2_profiler
756 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
757 COUNTERS[0] is incremented. */
759 void
760 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
762 if (value & (value - 1))
763 counters[0]++;
764 else
765 counters[1]++;
767 #endif
769 /* Tries to determine the most common value among its inputs. Checks if the
770 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
771 is incremented. If this is not the case and COUNTERS[1] is not zero,
772 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
773 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
774 function is called more than 50% of the time with one value, this value
775 will be in COUNTERS[0] in the end.
777 In any case, COUNTERS[2] is incremented. */
779 static inline void
780 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
782 if (value == counters[0])
783 counters[1]++;
784 else if (counters[1] == 0)
786 counters[1] = 1;
787 counters[0] = value;
789 else
790 counters[1]--;
791 counters[2]++;
794 #ifdef L_gcov_one_value_profiler
795 void
796 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
798 __gcov_one_value_profiler_body (counters, value);
800 #endif
802 #ifdef L_gcov_indirect_call_profiler
804 /* By default, the C++ compiler will use function addresses in the
805 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
806 tells the compiler to use function descriptors instead. The value
807 of this macro says how many words wide the descriptor is (normally 2),
808 but it may be dependent on target flags. Since we do not have access
809 to the target flags here we just check to see if it is set and use
810 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
812 It is assumed that the address of a function descriptor may be treated
813 as a pointer to a function. */
815 #ifdef TARGET_VTABLE_USES_DESCRIPTORS
816 #define VTABLE_USES_DESCRIPTORS 1
817 #else
818 #define VTABLE_USES_DESCRIPTORS 0
819 #endif
821 /* Tries to determine the most common value among its inputs. */
822 void
823 __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
824 void* cur_func, void* callee_func)
826 /* If the C++ virtual tables contain function descriptors then one
827 function may have multiple descriptors and we need to dereference
828 the descriptors to see if they point to the same function. */
829 if (cur_func == callee_func
830 || (VTABLE_USES_DESCRIPTORS && callee_func
831 && *(void **) cur_func == *(void **) callee_func))
832 __gcov_one_value_profiler_body (counter, value);
834 #endif
837 #ifdef L_gcov_average_profiler
838 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
839 to saturate up. */
841 void
842 __gcov_average_profiler (gcov_type *counters, gcov_type value)
844 counters[0] += value;
845 counters[1] ++;
847 #endif
849 #ifdef L_gcov_ior_profiler
850 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
851 to saturate up. */
853 void
854 __gcov_ior_profiler (gcov_type *counters, gcov_type value)
856 *counters |= value;
858 #endif
860 #ifdef L_gcov_fork
861 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
862 that they are not counted twice. */
864 pid_t
865 __gcov_fork (void)
867 __gcov_flush ();
868 return fork ();
870 #endif
872 #ifdef L_gcov_execl
873 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
874 that they are not lost. */
877 __gcov_execl (const char *path, char *arg, ...)
879 va_list ap, aq;
880 unsigned i, length;
881 char **args;
883 __gcov_flush ();
885 va_start (ap, arg);
886 va_copy (aq, ap);
888 length = 2;
889 while (va_arg (ap, char *))
890 length++;
891 va_end (ap);
893 args = (char **) alloca (length * sizeof (void *));
894 args[0] = arg;
895 for (i = 1; i < length; i++)
896 args[i] = va_arg (aq, char *);
897 va_end (aq);
899 return execv (path, args);
901 #endif
903 #ifdef L_gcov_execlp
904 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so
905 that they are not lost. */
908 __gcov_execlp (const char *path, char *arg, ...)
910 va_list ap, aq;
911 unsigned i, length;
912 char **args;
914 __gcov_flush ();
916 va_start (ap, arg);
917 va_copy (aq, ap);
919 length = 2;
920 while (va_arg (ap, char *))
921 length++;
922 va_end (ap);
924 args = (char **) alloca (length * sizeof (void *));
925 args[0] = arg;
926 for (i = 1; i < length; i++)
927 args[i] = va_arg (aq, char *);
928 va_end (aq);
930 return execvp (path, args);
932 #endif
934 #ifdef L_gcov_execle
935 /* A wrapper for the execle function. Flushes the accumulated profiling data, so
936 that they are not lost. */
939 __gcov_execle (const char *path, char *arg, ...)
941 va_list ap, aq;
942 unsigned i, length;
943 char **args;
944 char **envp;
946 __gcov_flush ();
948 va_start (ap, arg);
949 va_copy (aq, ap);
951 length = 2;
952 while (va_arg (ap, char *))
953 length++;
954 va_end (ap);
956 args = (char **) alloca (length * sizeof (void *));
957 args[0] = arg;
958 for (i = 1; i < length; i++)
959 args[i] = va_arg (aq, char *);
960 envp = va_arg (aq, char **);
961 va_end (aq);
963 return execve (path, args, envp);
965 #endif
967 #ifdef L_gcov_execv
968 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
969 that they are not lost. */
972 __gcov_execv (const char *path, char *const argv[])
974 __gcov_flush ();
975 return execv (path, argv);
977 #endif
979 #ifdef L_gcov_execvp
980 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so
981 that they are not lost. */
984 __gcov_execvp (const char *path, char *const argv[])
986 __gcov_flush ();
987 return execvp (path, argv);
989 #endif
991 #ifdef L_gcov_execve
992 /* A wrapper for the execve function. Flushes the accumulated profiling data, so
993 that they are not lost. */
996 __gcov_execve (const char *path, char *const argv[], char *const envp[])
998 __gcov_flush ();
999 return execve (path, argv, envp);
1001 #endif
1002 #endif /* inhibit_libc */