Fix a bug in cfg fixup
[official-gcc.git] / libgcc / libgcov.c
blobb39ef49343f5c44283e19cfdb3dafd6936890781
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 (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
288 /* If prefix is given, add directory separator. */
289 strcpy (gi_filename_up, "/");
290 strcpy (gi_filename_up + 1, fname);
292 else
293 strcpy (gi_filename_up, fname);
295 /* Totals for this object file. */
296 ci_ptr = gi_ptr->counts;
297 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
299 if (!((1 << t_ix) & gi_ptr->ctr_mask))
300 continue;
302 cs_ptr = &this_object.ctrs[t_ix];
303 cs_ptr->num += ci_ptr->num;
304 for (c_num = 0; c_num < ci_ptr->num; c_num++)
306 cs_ptr->sum_all += ci_ptr->values[c_num];
307 if (cs_ptr->run_max < ci_ptr->values[c_num])
308 cs_ptr->run_max = ci_ptr->values[c_num];
311 ci_ptr++;
314 c_ix = 0;
315 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
316 if ((1 << t_ix) & gi_ptr->ctr_mask)
318 values[c_ix] = gi_ptr->counts[c_ix].values;
319 c_ix++;
322 /* Calculate the function_info stride. This depends on the
323 number of counter types being measured. */
324 fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
325 if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
327 fi_stride += __alignof__ (struct gcov_fn_info) - 1;
328 fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
331 if (!gcov_open (gi_filename))
333 /* Open failed likely due to missed directory.
334 Create directory and retry to open file. */
335 if (create_file_directory (gi_filename))
337 fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
338 continue;
340 if (!gcov_open (gi_filename))
342 fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
343 continue;
347 tag = gcov_read_unsigned ();
348 if (tag)
350 /* Merge data from file. */
351 if (tag != GCOV_DATA_MAGIC)
353 fprintf (stderr, "profiling:%s:Not a gcov data file\n",
354 gi_filename);
355 goto read_fatal;
357 length = gcov_read_unsigned ();
358 if (!gcov_version (gi_ptr, length, gi_filename))
359 goto read_fatal;
361 length = gcov_read_unsigned ();
362 if (length != gi_ptr->stamp)
363 /* Read from a different compilation. Overwrite the file. */
364 goto rewrite;
366 /* Merge execution counts for each function. */
367 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
369 fi_ptr = (const struct gcov_fn_info *)
370 ((const char *) gi_ptr->functions + f_ix * fi_stride);
371 tag = gcov_read_unsigned ();
372 length = gcov_read_unsigned ();
374 /* Check function. */
375 if (tag != GCOV_TAG_FUNCTION
376 || length != GCOV_TAG_FUNCTION_LENGTH
377 || gcov_read_unsigned () != fi_ptr->ident
378 || gcov_read_unsigned () != fi_ptr->lineno_checksum
379 || gcov_read_unsigned () != fi_ptr->cfg_checksum)
381 read_mismatch:;
382 fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
383 gi_filename,
384 f_ix + 1 ? "function" : "summaries");
385 goto read_fatal;
388 c_ix = 0;
389 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
391 gcov_merge_fn merge;
393 if (!((1 << t_ix) & gi_ptr->ctr_mask))
394 continue;
396 n_counts = fi_ptr->n_ctrs[c_ix];
397 merge = gi_ptr->counts[c_ix].merge;
399 tag = gcov_read_unsigned ();
400 length = gcov_read_unsigned ();
401 if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
402 || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
403 goto read_mismatch;
404 (*merge) (values[c_ix], n_counts);
405 values[c_ix] += n_counts;
406 c_ix++;
408 if ((error = gcov_is_error ()))
409 goto read_error;
412 f_ix = ~0u;
413 /* Check program & object summary */
414 while (1)
416 int is_program;
418 eof_pos = gcov_position ();
419 tag = gcov_read_unsigned ();
420 if (!tag)
421 break;
423 length = gcov_read_unsigned ();
424 is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
425 if (length != GCOV_TAG_SUMMARY_LENGTH
426 || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
427 goto read_mismatch;
428 gcov_read_summary (is_program ? &program : &object);
429 if ((error = gcov_is_error ()))
430 goto read_error;
431 if (is_program && program.checksum == gcov_crc32)
433 summary_pos = eof_pos;
434 goto rewrite;
438 goto rewrite;
440 read_error:;
441 fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
442 : "profiling:%s:Error merging\n", gi_filename);
444 read_fatal:;
445 gcov_close ();
446 continue;
448 rewrite:;
449 gcov_rewrite ();
450 if (!summary_pos)
451 memset (&program, 0, sizeof (program));
453 /* Merge the summaries. */
454 f_ix = ~0u;
455 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
457 cs_obj = &object.ctrs[t_ix];
458 cs_tobj = &this_object.ctrs[t_ix];
459 cs_prg = &program.ctrs[t_ix];
460 cs_tprg = &this_program.ctrs[t_ix];
461 cs_all = &all.ctrs[t_ix];
463 if ((1 << t_ix) & gi_ptr->ctr_mask)
465 if (!cs_obj->runs++)
466 cs_obj->num = cs_tobj->num;
467 else if (cs_obj->num != cs_tobj->num)
468 goto read_mismatch;
469 cs_obj->sum_all += cs_tobj->sum_all;
470 if (cs_obj->run_max < cs_tobj->run_max)
471 cs_obj->run_max = cs_tobj->run_max;
472 cs_obj->sum_max += cs_tobj->run_max;
474 if (!cs_prg->runs++)
475 cs_prg->num = cs_tprg->num;
476 else if (cs_prg->num != cs_tprg->num)
477 goto read_mismatch;
478 cs_prg->sum_all += cs_tprg->sum_all;
479 if (cs_prg->run_max < cs_tprg->run_max)
480 cs_prg->run_max = cs_tprg->run_max;
481 cs_prg->sum_max += cs_tprg->run_max;
483 else if (cs_obj->num || cs_prg->num)
484 goto read_mismatch;
486 if (!cs_all->runs && cs_prg->runs)
487 memcpy (cs_all, cs_prg, sizeof (*cs_all));
488 else if (!all.checksum
489 && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
490 && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
492 fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
493 gi_filename, GCOV_LOCKED
494 ? "" : " or concurrent update without locking support");
495 all.checksum = ~0u;
499 c_ix = 0;
500 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
501 if ((1 << t_ix) & gi_ptr->ctr_mask)
503 values[c_ix] = gi_ptr->counts[c_ix].values;
504 c_ix++;
507 program.checksum = gcov_crc32;
509 /* Write out the data. */
510 gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
511 gcov_write_unsigned (gi_ptr->stamp);
513 /* Write execution counts for each function. */
514 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
516 fi_ptr = (const struct gcov_fn_info *)
517 ((const char *) gi_ptr->functions + f_ix * fi_stride);
519 /* Announce function. */
520 gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
521 gcov_write_unsigned (fi_ptr->ident);
522 gcov_write_unsigned (fi_ptr->lineno_checksum);
523 gcov_write_unsigned (fi_ptr->cfg_checksum);
525 c_ix = 0;
526 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
528 gcov_type *c_ptr;
530 if (!((1 << t_ix) & gi_ptr->ctr_mask))
531 continue;
533 n_counts = fi_ptr->n_ctrs[c_ix];
535 gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
536 GCOV_TAG_COUNTER_LENGTH (n_counts));
537 c_ptr = values[c_ix];
538 while (n_counts--)
539 gcov_write_counter (*c_ptr++);
541 values[c_ix] = c_ptr;
542 c_ix++;
546 /* Object file summary. */
547 gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
549 /* Generate whole program statistics. */
550 if (eof_pos)
551 gcov_seek (eof_pos);
552 gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
553 if (!summary_pos)
554 gcov_write_unsigned (0);
555 if ((error = gcov_close ()))
556 fprintf (stderr, error < 0 ?
557 "profiling:%s:Overflow writing\n" :
558 "profiling:%s:Error writing\n",
559 gi_filename);
563 /* Add a new object file onto the bb chain. Invoked automatically
564 when running an object file's global ctors. */
566 void
567 __gcov_init (struct gcov_info *info)
569 if (!info->version)
570 return;
571 if (gcov_version (info, info->version, 0))
573 const char *ptr = info->filename;
574 gcov_unsigned_t crc32 = gcov_crc32;
575 size_t filename_length = strlen(info->filename);
577 /* Refresh the longest file name information */
578 if (filename_length > gcov_max_filename)
579 gcov_max_filename = filename_length;
583 unsigned ix;
584 gcov_unsigned_t value = *ptr << 24;
586 for (ix = 8; ix--; value <<= 1)
588 gcov_unsigned_t feedback;
590 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
591 crc32 <<= 1;
592 crc32 ^= feedback;
595 while (*ptr++);
597 gcov_crc32 = crc32;
599 if (!gcov_list)
600 atexit (gcov_exit);
602 info->next = gcov_list;
603 gcov_list = info;
605 info->version = 0;
608 /* Called before fork or exec - write out profile information gathered so
609 far and reset it to zero. This avoids duplication or loss of the
610 profile information gathered so far. */
612 void
613 __gcov_flush (void)
615 const struct gcov_info *gi_ptr;
617 gcov_exit ();
618 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
620 unsigned t_ix;
621 const struct gcov_ctr_info *ci_ptr;
623 for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
624 if ((1 << t_ix) & gi_ptr->ctr_mask)
626 memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
627 ci_ptr++;
632 #endif /* L_gcov */
634 #ifdef L_gcov_merge_add
635 /* The profile merging function that just adds the counters. It is given
636 an array COUNTERS of N_COUNTERS old counters and it reads the same number
637 of counters from the gcov file. */
638 void
639 __gcov_merge_add (gcov_type *counters, unsigned n_counters)
641 for (; n_counters; counters++, n_counters--)
642 *counters += gcov_read_counter ();
644 #endif /* L_gcov_merge_add */
646 #ifdef L_gcov_merge_ior
647 /* The profile merging function that just adds the counters. It is given
648 an array COUNTERS of N_COUNTERS old counters and it reads the same number
649 of counters from the gcov file. */
650 void
651 __gcov_merge_ior (gcov_type *counters, unsigned n_counters)
653 for (; n_counters; counters++, n_counters--)
654 *counters |= gcov_read_counter ();
656 #endif
658 #ifdef L_gcov_merge_single
659 /* The profile merging function for choosing the most common value.
660 It is given an array COUNTERS of N_COUNTERS old counters and it
661 reads the same number of counters from the gcov file. The counters
662 are split into 3-tuples where the members of the tuple have
663 meanings:
665 -- the stored candidate on the most common value of the measured entity
666 -- counter
667 -- total number of evaluations of the value */
668 void
669 __gcov_merge_single (gcov_type *counters, unsigned n_counters)
671 unsigned i, n_measures;
672 gcov_type value, counter, all;
674 gcc_assert (!(n_counters % 3));
675 n_measures = n_counters / 3;
676 for (i = 0; i < n_measures; i++, counters += 3)
678 value = gcov_read_counter ();
679 counter = gcov_read_counter ();
680 all = gcov_read_counter ();
682 if (counters[0] == value)
683 counters[1] += counter;
684 else if (counter > counters[1])
686 counters[0] = value;
687 counters[1] = counter - counters[1];
689 else
690 counters[1] -= counter;
691 counters[2] += all;
694 #endif /* L_gcov_merge_single */
696 #ifdef L_gcov_merge_delta
697 /* The profile merging function for choosing the most common
698 difference between two consecutive evaluations of the value. It is
699 given an array COUNTERS of N_COUNTERS old counters and it reads the
700 same number of counters from the gcov file. The counters are split
701 into 4-tuples where the members of the tuple have meanings:
703 -- the last value of the measured entity
704 -- the stored candidate on the most common difference
705 -- counter
706 -- total number of evaluations of the value */
707 void
708 __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
710 unsigned i, n_measures;
711 gcov_type value, counter, all;
713 gcc_assert (!(n_counters % 4));
714 n_measures = n_counters / 4;
715 for (i = 0; i < n_measures; i++, counters += 4)
717 /* last = */ gcov_read_counter ();
718 value = gcov_read_counter ();
719 counter = gcov_read_counter ();
720 all = gcov_read_counter ();
722 if (counters[1] == value)
723 counters[2] += counter;
724 else if (counter > counters[2])
726 counters[1] = value;
727 counters[2] = counter - counters[2];
729 else
730 counters[2] -= counter;
731 counters[3] += all;
734 #endif /* L_gcov_merge_delta */
736 #ifdef L_gcov_interval_profiler
737 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
738 corresponding counter in COUNTERS. If the VALUE is above or below
739 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
740 instead. */
742 void
743 __gcov_interval_profiler (gcov_type *counters, gcov_type value,
744 int start, unsigned steps)
746 gcov_type delta = value - start;
747 if (delta < 0)
748 counters[steps + 1]++;
749 else if (delta >= steps)
750 counters[steps]++;
751 else
752 counters[delta]++;
754 #endif
756 #ifdef L_gcov_pow2_profiler
757 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
758 COUNTERS[0] is incremented. */
760 void
761 __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
763 if (value & (value - 1))
764 counters[0]++;
765 else
766 counters[1]++;
768 #endif
770 /* Tries to determine the most common value among its inputs. Checks if the
771 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
772 is incremented. If this is not the case and COUNTERS[1] is not zero,
773 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
774 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
775 function is called more than 50% of the time with one value, this value
776 will be in COUNTERS[0] in the end.
778 In any case, COUNTERS[2] is incremented. */
780 static inline void
781 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
783 if (value == counters[0])
784 counters[1]++;
785 else if (counters[1] == 0)
787 counters[1] = 1;
788 counters[0] = value;
790 else
791 counters[1]--;
792 counters[2]++;
795 #ifdef L_gcov_one_value_profiler
796 void
797 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
799 __gcov_one_value_profiler_body (counters, value);
801 #endif
803 #ifdef L_gcov_indirect_call_profiler
805 /* By default, the C++ compiler will use function addresses in the
806 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
807 tells the compiler to use function descriptors instead. The value
808 of this macro says how many words wide the descriptor is (normally 2),
809 but it may be dependent on target flags. Since we do not have access
810 to the target flags here we just check to see if it is set and use
811 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
813 It is assumed that the address of a function descriptor may be treated
814 as a pointer to a function. */
816 #ifdef TARGET_VTABLE_USES_DESCRIPTORS
817 #define VTABLE_USES_DESCRIPTORS 1
818 #else
819 #define VTABLE_USES_DESCRIPTORS 0
820 #endif
822 /* Tries to determine the most common value among its inputs. */
823 void
824 __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
825 void* cur_func, void* callee_func)
827 /* If the C++ virtual tables contain function descriptors then one
828 function may have multiple descriptors and we need to dereference
829 the descriptors to see if they point to the same function. */
830 if (cur_func == callee_func
831 || (VTABLE_USES_DESCRIPTORS && callee_func
832 && *(void **) cur_func == *(void **) callee_func))
833 __gcov_one_value_profiler_body (counter, value);
835 #endif
838 #ifdef L_gcov_average_profiler
839 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
840 to saturate up. */
842 void
843 __gcov_average_profiler (gcov_type *counters, gcov_type value)
845 counters[0] += value;
846 counters[1] ++;
848 #endif
850 #ifdef L_gcov_ior_profiler
851 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
852 to saturate up. */
854 void
855 __gcov_ior_profiler (gcov_type *counters, gcov_type value)
857 *counters |= value;
859 #endif
861 #ifdef L_gcov_fork
862 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
863 that they are not counted twice. */
865 pid_t
866 __gcov_fork (void)
868 __gcov_flush ();
869 return fork ();
871 #endif
873 #ifdef L_gcov_execl
874 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
875 that they are not lost. */
878 __gcov_execl (const char *path, char *arg, ...)
880 va_list ap, aq;
881 unsigned i, length;
882 char **args;
884 __gcov_flush ();
886 va_start (ap, arg);
887 va_copy (aq, ap);
889 length = 2;
890 while (va_arg (ap, char *))
891 length++;
892 va_end (ap);
894 args = (char **) alloca (length * sizeof (void *));
895 args[0] = arg;
896 for (i = 1; i < length; i++)
897 args[i] = va_arg (aq, char *);
898 va_end (aq);
900 return execv (path, args);
902 #endif
904 #ifdef L_gcov_execlp
905 /* A wrapper for the execlp function. Flushes the accumulated profiling data, so
906 that they are not lost. */
909 __gcov_execlp (const char *path, char *arg, ...)
911 va_list ap, aq;
912 unsigned i, length;
913 char **args;
915 __gcov_flush ();
917 va_start (ap, arg);
918 va_copy (aq, ap);
920 length = 2;
921 while (va_arg (ap, char *))
922 length++;
923 va_end (ap);
925 args = (char **) alloca (length * sizeof (void *));
926 args[0] = arg;
927 for (i = 1; i < length; i++)
928 args[i] = va_arg (aq, char *);
929 va_end (aq);
931 return execvp (path, args);
933 #endif
935 #ifdef L_gcov_execle
936 /* A wrapper for the execle function. Flushes the accumulated profiling data, so
937 that they are not lost. */
940 __gcov_execle (const char *path, char *arg, ...)
942 va_list ap, aq;
943 unsigned i, length;
944 char **args;
945 char **envp;
947 __gcov_flush ();
949 va_start (ap, arg);
950 va_copy (aq, ap);
952 length = 2;
953 while (va_arg (ap, char *))
954 length++;
955 va_end (ap);
957 args = (char **) alloca (length * sizeof (void *));
958 args[0] = arg;
959 for (i = 1; i < length; i++)
960 args[i] = va_arg (aq, char *);
961 envp = va_arg (aq, char **);
962 va_end (aq);
964 return execve (path, args, envp);
966 #endif
968 #ifdef L_gcov_execv
969 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
970 that they are not lost. */
973 __gcov_execv (const char *path, char *const argv[])
975 __gcov_flush ();
976 return execv (path, argv);
978 #endif
980 #ifdef L_gcov_execvp
981 /* A wrapper for the execvp function. Flushes the accumulated profiling data, so
982 that they are not lost. */
985 __gcov_execvp (const char *path, char *const argv[])
987 __gcov_flush ();
988 return execvp (path, argv);
990 #endif
992 #ifdef L_gcov_execve
993 /* A wrapper for the execve function. Flushes the accumulated profiling data, so
994 that they are not lost. */
997 __gcov_execve (const char *path, char *const argv[], char *const envp[])
999 __gcov_flush ();
1000 return execve (path, argv, envp);
1002 #endif
1003 #endif /* inhibit_libc */