soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / lib / libgcov.c
blobb0c816181d1ee357dfd291a1e2612c46ee499fdf
1 /* SPDX-License-Identifier: GPL-3.0-only WITH GCC-exception-3.1 */
3 /* Routines required for instrumenting a program. */
4 /* Compile this one with gcc. */
5 /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
6 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010, 2011
7 Free Software Foundation, Inc.
9 This file is part of GCC.
11 GCC is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 3, or (at your option) any later
14 version.
16 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 for more details.
21 Under Section 7 of GPL version 3, you are granted additional
22 permissions described in the GCC Runtime Library Exception, version
23 3.1, as published by the Free Software Foundation.
26 #define __COREBOOT__
27 #ifdef __COREBOOT__
28 #include <stdlib.h>
29 #include <string.h>
30 #include <commonlib/helpers.h>
31 #include <console/console.h>
32 #include <assert.h>
33 typedef s32 pid_t;
34 #define gcc_assert(x) ASSERT(x)
35 #define fprintf(file, x...) printk(BIOS_ERR, x)
36 #include "gcov-glue.c"
38 /* Define MACROs to be used by coreboot compilation. */
39 # define L_gcov
40 # define L_gcov_interval_profiler
41 # define L_gcov_pow2_profiler
42 # define L_gcov_one_value_profiler
43 # define L_gcov_indirect_call_profiler
44 # define L_gcov_average_profiler
45 # define L_gcov_ior_profiler
47 # define HAVE_CC_TLS 0
48 # define __GCOV_KERNEL__
50 # define IN_LIBGCOV 1
51 # define IN_GCOV 0
52 #else /* __COREBOOT__ */
53 #include "tconfig.h"
54 #include "tsystem.h"
55 #include "coretypes.h"
56 #include "tm.h"
57 #include "libgcc_tm.h"
58 #endif /* __COREBOOT__ */
60 #ifndef __COREBOOT__
61 #if defined(inhibit_libc)
62 #define IN_LIBGCOV (-1)
63 #else
64 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
65 #include <stdio.h>
66 #define IN_LIBGCOV 1
67 #if defined(L_gcov)
68 #define GCOV_LINKAGE /* nothing */
69 #endif
70 #endif
71 #endif /* __COREBOOT__ */
72 #include "gcov-io.h"
74 #if defined(inhibit_libc)
75 /* If libc and its header files are not available, provide dummy functions. */
77 #ifdef L_gcov
78 void __gcov_init(struct gcov_info *p __attribute__((unused))) {}
79 void __gcov_flush(void) {}
80 #endif
82 #ifdef L_gcov_merge_add
83 void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
84 unsigned int n_counters __attribute__((unused))) {}
85 #endif
87 #ifdef L_gcov_merge_single
88 void __gcov_merge_single(gcov_type *counters __attribute__((unused)),
89 unsigned int n_counters __attribute__((unused))) {}
90 #endif
92 #ifdef L_gcov_merge_delta
93 void __gcov_merge_delta(gcov_type *counters __attribute__((unused)),
94 unsigned int n_counters __attribute__((unused))) {}
95 #endif
97 #else
99 #ifndef __COREBOOT__
100 #include <string.h>
101 #if GCOV_LOCKED
102 #include <fcntl.h>
103 #include <errno.h>
104 #include <sys/stat.h>
105 #endif
106 #else
107 void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
108 unsigned int n_counters __attribute__((unused))) {}
109 #endif /* __COREBOOT__ */
111 #ifdef L_gcov
112 #include "gcov-io.c"
114 struct gcov_fn_buffer {
115 struct gcov_fn_buffer *next;
116 unsigned int fn_ix;
117 struct gcov_fn_info info;
118 /* note gcov_fn_info ends in a trailing array. */
121 /* Chain of per-object gcov structures. */
122 static struct gcov_info *gcov_list;
124 /* Size of the longest file name. */
125 static size_t gcov_max_filename = 0;
127 /* Make sure path component of the given FILENAME exists, create
128 missing directories. FILENAME must be writable.
129 Returns zero on success, or -1 if an error occurred. */
131 static int
132 create_file_directory(char *filename)
134 #ifdef __COREBOOT__
135 (void) filename;
136 return 0;
137 #else
138 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
139 (void) filename;
140 return -1;
141 #else
142 char *s;
144 s = filename;
146 if (HAS_DRIVE_SPEC(s))
147 s += 2;
148 if (IS_DIR_SEPARATOR(*s))
149 ++s;
150 for (; *s != '\0'; s++)
151 if (IS_DIR_SEPARATOR(*s)) {
152 char sep = *s;
153 *s = '\0';
155 /* Try to make directory if it doesn't already exist. */
156 if (access(filename, F_OK) == -1
157 #ifdef TARGET_POSIX_IO
158 && mkdir(filename, 0755) == -1
159 #else
160 && mkdir(filename) == -1
161 #endif
162 /* The directory might have been made by another
163 * process.
165 && errno != EEXIST) {
166 fprintf(stderr,
167 "profiling:%s:Cannot create directory\n",
168 filename);
169 *s = sep;
170 return -1;
173 *s = sep;
175 return 0;
176 #endif
177 #endif
180 static struct gcov_fn_buffer *
181 free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
182 unsigned int limit)
184 struct gcov_fn_buffer *next;
185 unsigned int ix, n_ctr = 0;
187 if (!buffer)
188 return 0;
189 next = buffer->next;
191 for (ix = 0; ix != limit; ix++)
192 if (gi_ptr->merge[ix])
193 free(buffer->info.ctrs[n_ctr++].values);
194 free(buffer);
195 return next;
198 static struct gcov_fn_buffer **
199 buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr,
200 struct gcov_fn_buffer **end_ptr, unsigned int fn_ix)
202 unsigned int n_ctrs = 0, ix = 0;
203 struct gcov_fn_buffer *fn_buffer;
204 unsigned int len;
206 for (ix = GCOV_COUNTERS; ix--;)
207 if (gi_ptr->merge[ix])
208 n_ctrs++;
210 len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs;
211 fn_buffer = (struct gcov_fn_buffer *)malloc(len);
213 if (!fn_buffer)
214 goto fail;
216 fn_buffer->next = 0;
217 fn_buffer->fn_ix = fn_ix;
218 fn_buffer->info.ident = gcov_read_unsigned();
219 fn_buffer->info.lineno_checksum = gcov_read_unsigned();
220 fn_buffer->info.cfg_checksum = gcov_read_unsigned();
222 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) {
223 gcov_unsigned_t length;
224 gcov_type *values;
226 if (!gi_ptr->merge[ix])
227 continue;
229 if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) {
230 len = 0;
231 goto fail;
234 length = GCOV_TAG_COUNTER_NUM(gcov_read_unsigned());
235 len = length * sizeof(gcov_type);
236 values = (gcov_type *)malloc(len);
237 if (!values)
238 goto fail;
240 fn_buffer->info.ctrs[n_ctrs].num = length;
241 fn_buffer->info.ctrs[n_ctrs].values = values;
243 while (length--)
244 *values++ = gcov_read_counter();
245 n_ctrs++;
248 *end_ptr = fn_buffer;
249 return &fn_buffer->next;
251 fail:
252 fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix,
253 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
255 return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix);
258 /* Add an unsigned value to the current crc */
260 static gcov_unsigned_t
261 crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value)
263 unsigned int ix;
265 for (ix = 32; ix--; value <<= 1) {
266 unsigned int feedback;
268 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
269 crc32 <<= 1;
270 crc32 ^= feedback;
273 return crc32;
276 /* Check if VERSION of the info block PTR matches libgcov one.
277 Return 1 on success, or zero in case of versions mismatch.
278 If FILENAME is not NULL, its value used for reporting purposes
279 instead of value from the info block. */
281 static int
282 gcov_version(struct gcov_info *ptr, gcov_unsigned_t version,
283 const char *filename)
285 if (version != GCOV_VERSION) {
286 char v[4], e[4];
288 GCOV_UNSIGNED2STRING(v, version);
289 GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
291 fprintf(stderr,
292 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
293 filename ? filename : ptr->filename, e, v);
294 return 0;
296 return 1;
299 /* Dump the coverage counts. We merge with existing counts when
300 possible, to avoid growing the .da files ad infinitum. We use this
301 program's checksum to make sure we only accumulate whole program
302 statistics to the correct summary. An object file might be embedded
303 in two separate programs, and we must keep the two program
304 summaries separate. */
306 static void
307 gcov_exit(void)
309 struct gcov_info *gi_ptr;
310 const struct gcov_fn_info *gfi_ptr;
311 struct gcov_summary this_prg; /* summary for program. */
312 struct gcov_summary all_prg; /* summary for all instances of program. */
313 struct gcov_ctr_summary *cs_ptr;
314 const struct gcov_ctr_info *ci_ptr;
315 unsigned int t_ix;
316 int f_ix = 0;
317 gcov_unsigned_t c_num;
318 const char *gcov_prefix;
319 int gcov_prefix_strip = 0;
320 size_t prefix_length;
321 char *gi_filename, *gi_filename_up;
322 gcov_unsigned_t crc32 = 0;
324 memset(&all_prg, 0, sizeof(all_prg));
325 /* Find the totals for this execution. */
326 memset(&this_prg, 0, sizeof(this_prg));
327 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
328 crc32 = crc32_unsigned(crc32, gi_ptr->stamp);
329 crc32 = crc32_unsigned(crc32, gi_ptr->n_functions);
331 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
332 f_ix++) {
333 gfi_ptr = gi_ptr->functions[f_ix];
335 if (gfi_ptr && gfi_ptr->key != gi_ptr)
336 gfi_ptr = 0;
338 crc32 = crc32_unsigned(crc32, gfi_ptr
339 ? gfi_ptr->cfg_checksum : 0);
340 crc32 = crc32_unsigned(crc32,
341 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
342 if (!gfi_ptr)
343 continue;
345 ci_ptr = gfi_ptr->ctrs;
346 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) {
347 if (!gi_ptr->merge[t_ix])
348 continue;
350 cs_ptr = &this_prg.ctrs[t_ix];
351 cs_ptr->num += ci_ptr->num;
352 crc32 = crc32_unsigned(crc32, ci_ptr->num);
354 for (c_num = 0; c_num < ci_ptr->num; c_num++) {
355 cs_ptr->sum_all +=
356 ci_ptr->values[c_num];
357 if (cs_ptr->run_max
358 < ci_ptr->values[c_num])
359 cs_ptr->run_max =
360 ci_ptr->values[c_num];
362 ci_ptr++;
367 #ifndef __COREBOOT__
369 /* Check if the level of dirs to strip off specified. */
370 char *tmp = getenv("GCOV_PREFIX_STRIP");
371 if (tmp) {
372 gcov_prefix_strip = atoi(tmp);
373 /* Do not consider negative values. */
374 if (gcov_prefix_strip < 0)
375 gcov_prefix_strip = 0;
379 /* Get file name relocation prefix. Non-absolute values are ignored. */
380 gcov_prefix = getenv("GCOV_PREFIX");
381 if (gcov_prefix) {
382 prefix_length = strlen(gcov_prefix);
384 /* Remove an unnecessary trailing '/' */
385 if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1]))
386 prefix_length--;
387 } else
388 #endif
389 prefix_length = 0;
391 /* If no prefix was specified and a prefix strip, then we assume
392 relative. */
393 if (gcov_prefix_strip != 0 && prefix_length == 0) {
394 gcov_prefix = ".";
395 prefix_length = 1;
397 /* Allocate and initialize the filename scratch space plus one. */
398 gi_filename = (char *) alloca(prefix_length + gcov_max_filename + 2);
399 if (prefix_length)
400 memcpy(gi_filename, gcov_prefix, prefix_length);
401 gi_filename_up = gi_filename + prefix_length;
403 /* Now merge each file. */
404 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
405 unsigned int n_counts;
406 struct gcov_summary prg; /* summary for this object over all
407 program. */
408 struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
409 int error = 0;
410 gcov_unsigned_t tag, length;
411 gcov_position_t summary_pos = 0;
412 gcov_position_t eof_pos = 0;
413 const char *fname, *s;
414 struct gcov_fn_buffer *fn_buffer = NULL;
415 struct gcov_fn_buffer **fn_tail = &fn_buffer;
417 fname = gi_ptr->filename;
419 /* Avoid to add multiple drive letters into combined path. */
420 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
421 fname += 2;
423 /* Build relocated filename, stripping off leading
424 * directories from the initial filename if requested.
426 if (gcov_prefix_strip > 0) {
427 int level = 0;
429 s = fname;
430 if (IS_DIR_SEPARATOR(*s))
431 ++s;
433 /* Skip selected directory levels. */
434 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
435 if (IS_DIR_SEPARATOR(*s)) {
436 fname = s;
437 level++;
441 /* Update complete filename with stripped original. */
442 if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) {
443 /* If prefix is given, add directory separator.
445 strcpy(gi_filename_up, "/");
446 strcpy(gi_filename_up + 1, fname);
447 } else
448 strcpy(gi_filename_up, fname);
450 if (!gcov_open(gi_filename)) {
451 /* Open failed likely due to missed directory.
452 * Create directory and retry to open file.
454 if (create_file_directory(gi_filename)) {
455 fprintf(stderr, "profiling:%s:Skip\n",
456 gi_filename);
457 continue;
459 if (!gcov_open(gi_filename)) {
460 fprintf(stderr,
461 "profiling:%s:Cannot open\n",
462 gi_filename);
463 continue;
467 tag = gcov_read_unsigned();
468 if (tag) {
469 /* Merge data from file. */
470 if (tag != GCOV_DATA_MAGIC) {
471 fprintf(stderr,
472 "profiling:%s:Not a gcov data file\n",
473 gi_filename);
474 goto read_fatal;
476 length = gcov_read_unsigned();
477 if (!gcov_version(gi_ptr, length, gi_filename))
478 goto read_fatal;
480 length = gcov_read_unsigned();
481 if (length != gi_ptr->stamp)
482 /* Read from a different compilation.
483 * Overwrite the file.
485 goto rewrite;
487 /* Look for program summary. */
488 for (f_ix = 0;;) {
489 struct gcov_summary tmp;
491 eof_pos = gcov_position();
492 tag = gcov_read_unsigned();
493 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
494 break;
496 f_ix--;
497 length = gcov_read_unsigned();
498 if (length != GCOV_TAG_SUMMARY_LENGTH)
499 goto read_mismatch;
500 gcov_read_summary(&tmp);
501 error = gcov_is_error();
502 if (error)
503 goto read_error;
504 if (summary_pos
505 || tmp.checksum != crc32)
506 goto next_summary;
508 for (t_ix = 0; t_ix !=
509 GCOV_COUNTERS_SUMMABLE; t_ix++)
510 if (tmp.ctrs[t_ix].num !=
511 this_prg.ctrs[t_ix].num)
512 goto next_summary;
513 prg = tmp;
514 summary_pos = eof_pos;
516 next_summary:;
519 /* Merge execution counts for each function. */
520 for (f_ix = 0; (unsigned int)f_ix !=
521 gi_ptr->n_functions;
522 f_ix++, tag = gcov_read_unsigned()) {
523 gfi_ptr = gi_ptr->functions[f_ix];
525 if (tag != GCOV_TAG_FUNCTION)
526 goto read_mismatch;
528 length = gcov_read_unsigned();
529 if (!length)
530 /* This function did not appear
531 * in the other program. We
532 * have nothing to merge.
534 continue;
536 if (length != GCOV_TAG_FUNCTION_LENGTH)
537 goto read_mismatch;
539 if (!gfi_ptr || gfi_ptr->key !=
540 gi_ptr) {
541 /* This function appears in the
542 * other program. We need to
543 * buffer the information in
544 * order to write it back out --
545 * we'll be inserting data
546 * before this point, so cannot
547 * simply keep the data in the
548 * file.
550 fn_tail = buffer_fn_data(
551 gi_filename, gi_ptr,
552 fn_tail, f_ix);
553 if (!fn_tail)
554 goto read_mismatch;
555 continue;
558 length = gcov_read_unsigned();
559 if (length != gfi_ptr->ident)
560 goto read_mismatch;
562 length = gcov_read_unsigned();
563 if (length != gfi_ptr->lineno_checksum)
564 goto read_mismatch;
566 length = gcov_read_unsigned();
567 if (length != gfi_ptr->cfg_checksum)
568 goto read_mismatch;
570 ci_ptr = gfi_ptr->ctrs;
571 for (t_ix = 0; t_ix < GCOV_COUNTERS;
572 t_ix++) {
573 gcov_merge_fn merge =
574 gi_ptr->merge[t_ix];
576 if (!merge)
577 continue;
579 tag = gcov_read_unsigned();
580 length = gcov_read_unsigned();
581 if (tag != GCOV_TAG_FOR_COUNTER(
582 t_ix) || length !=
583 GCOV_TAG_COUNTER_LENGTH(
584 ci_ptr->num))
585 goto read_mismatch;
586 (*merge)(ci_ptr->values,
587 ci_ptr->num);
588 ci_ptr++;
590 error = gcov_is_error();
591 if (error)
592 goto read_error;
595 if (tag) {
596 read_mismatch:;
597 fprintf(stderr,
598 "profiling:%s:Merge mismatch for %s %u\n",
599 gi_filename, f_ix >= 0 ?
600 "function" : "summary",
601 f_ix < 0 ? -1 - f_ix : f_ix);
602 goto read_fatal;
605 goto rewrite;
607 read_error:;
608 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
609 error < 0 ? "Overflow" : "Error");
611 goto read_fatal;
613 rewrite:;
614 gcov_rewrite();
615 if (!summary_pos) {
616 memset(&prg, 0, sizeof(prg));
617 summary_pos = eof_pos;
620 /* Merge the summaries. */
621 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) {
622 cs_prg = &prg.ctrs[t_ix];
623 cs_tprg = &this_prg.ctrs[t_ix];
624 cs_all = &all_prg.ctrs[t_ix];
626 if (gi_ptr->merge[t_ix]) {
627 if (!cs_prg->runs++)
628 cs_prg->num = cs_tprg->num;
629 cs_prg->sum_all += cs_tprg->sum_all;
630 if (cs_prg->run_max < cs_tprg->run_max)
631 cs_prg->run_max = cs_tprg->run_max;
632 cs_prg->sum_max += cs_tprg->run_max;
633 } else if (cs_prg->runs)
634 goto read_mismatch;
636 if (!cs_all->runs && cs_prg->runs)
637 memcpy(cs_all, cs_prg, sizeof(*cs_all));
638 else if (!all_prg.checksum
639 && (!GCOV_LOCKED
640 || cs_all->runs == cs_prg->runs)
641 && memcmp(cs_all, cs_prg, sizeof(*cs_all))) {
642 fprintf(stderr,
643 "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
644 gi_filename, GCOV_LOCKED ? "" :
645 " or concurrently updated without locking support");
646 all_prg.checksum = ~0u;
650 prg.checksum = crc32;
652 /* Write out the data. */
653 if (!eof_pos) {
654 gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
655 gcov_write_unsigned(gi_ptr->stamp);
658 if (summary_pos)
659 gcov_seek(summary_pos);
661 /* Generate whole program statistics. */
662 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
664 if (summary_pos < eof_pos)
665 gcov_seek(eof_pos);
667 /* Write execution counts for each function. */
668 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
669 f_ix++) {
670 unsigned int buffered = 0;
672 if (fn_buffer && fn_buffer->fn_ix
673 == (unsigned int)f_ix) {
674 /* Buffered data from another program. */
675 buffered = 1;
676 gfi_ptr = &fn_buffer->info;
677 length = GCOV_TAG_FUNCTION_LENGTH;
678 } else {
679 gfi_ptr = gi_ptr->functions[f_ix];
680 if (gfi_ptr && gfi_ptr->key == gi_ptr)
681 length = GCOV_TAG_FUNCTION_LENGTH;
682 else
683 length = 0;
686 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
687 if (!length)
688 continue;
690 gcov_write_unsigned(gfi_ptr->ident);
691 gcov_write_unsigned(gfi_ptr->lineno_checksum);
692 gcov_write_unsigned(gfi_ptr->cfg_checksum);
694 ci_ptr = gfi_ptr->ctrs;
695 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) {
696 if (!gi_ptr->merge[t_ix])
697 continue;
699 n_counts = ci_ptr->num;
700 gcov_write_tag_length(
701 GCOV_TAG_FOR_COUNTER(t_ix),
702 GCOV_TAG_COUNTER_LENGTH(n_counts));
703 gcov_type *c_ptr = ci_ptr->values;
704 while (n_counts--)
705 gcov_write_counter(*c_ptr++);
706 ci_ptr++;
708 if (buffered)
709 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
710 GCOV_COUNTERS);
713 gcov_write_unsigned(0);
715 read_fatal:;
716 while (fn_buffer)
717 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
718 GCOV_COUNTERS);
720 error = gcov_close();
721 if (error)
722 fprintf(stderr, error < 0 ?
723 "profiling:%s:Overflow writing\n" :
724 "profiling:%s:Error writing\n",
725 gi_filename);
729 /* Add a new object file onto the bb chain. Invoked automatically
730 when running an object file's global ctors. */
732 void
733 __gcov_init(struct gcov_info *info)
735 if (!info->version || !info->n_functions)
736 return;
737 if (gcov_version(info, info->version, 0)) {
738 size_t filename_length = strlen(info->filename);
740 /* Refresh the longest file name information */
741 if (filename_length > gcov_max_filename)
742 gcov_max_filename = filename_length;
744 #ifndef __COREBOOT__
745 if (!gcov_list)
746 atexit(gcov_exit);
747 #endif
749 info->next = gcov_list;
750 gcov_list = info;
752 info->version = 0;
755 /* Called before fork or exec - write out profile information gathered so
756 far and reset it to zero. This avoids duplication or loss of the
757 profile information gathered so far. */
759 void
760 __gcov_flush(void)
762 const struct gcov_info *gi_ptr;
764 gcov_exit();
765 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
766 unsigned int f_ix;
768 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) {
769 unsigned int t_ix;
770 const struct gcov_fn_info *gfi_ptr =
771 gi_ptr->functions[f_ix];
773 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
774 continue;
775 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
776 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) {
777 if (!gi_ptr->merge[t_ix])
778 continue;
780 memset(ci_ptr->values, 0,
781 sizeof(gcov_type) * ci_ptr->num);
782 ci_ptr++;
788 #endif /* L_gcov */
790 #ifdef L_gcov_merge_add
791 /* The profile merging function that just adds the counters. It is given
792 an array COUNTERS of N_COUNTERS old counters and it reads the same number
793 of counters from the gcov file. */
794 void
795 __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
797 for (; n_counters; counters++, n_counters--)
798 *counters += gcov_read_counter();
800 #endif /* L_gcov_merge_add */
802 #ifdef L_gcov_merge_ior
803 /* The profile merging function that just adds the counters. It is given
804 an array COUNTERS of N_COUNTERS old counters and it reads the same number
805 of counters from the gcov file. */
806 void
807 __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
809 for (; n_counters; counters++, n_counters--)
810 *counters |= gcov_read_counter();
812 #endif
814 #ifdef L_gcov_merge_single
815 /* The profile merging function for choosing the most common value.
816 * It is given an array COUNTERS of N_COUNTERS old counters and it
817 * reads the same number of counters from the gcov file. The counters
818 * are split into 3-tuples where the members of the tuple have
819 * meanings:
821 * -- the stored candidate on the most common value of the measured entity
822 * -- counter
823 * -- total number of evaluations of the value
825 void
826 __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
828 unsigned int i, n_measures;
829 gcov_type value, counter, all;
831 gcc_assert(!(n_counters % 3));
832 n_measures = n_counters / 3;
833 for (i = 0; i < n_measures; i++, counters += 3) {
834 value = gcov_read_counter();
835 counter = gcov_read_counter();
836 all = gcov_read_counter();
838 if (counters[0] == value)
839 counters[1] += counter;
840 else if (counter > counters[1]) {
841 counters[0] = value;
842 counters[1] = counter - counters[1];
843 } else
844 counters[1] -= counter;
845 counters[2] += all;
848 #endif /* L_gcov_merge_single */
850 #ifdef L_gcov_merge_delta
851 /* The profile merging function for choosing the most common
852 * difference between two consecutive evaluations of the value. It is
853 * given an array COUNTERS of N_COUNTERS old counters and it reads the
854 * same number of counters from the gcov file. The counters are split
855 * into 4-tuples where the members of the tuple have meanings:
857 * -- the last value of the measured entity
858 * -- the stored candidate on the most common difference
859 * -- counter
860 * -- total number of evaluations of the value
862 void
863 __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
865 unsigned int i, n_measures;
866 gcov_type value, counter, all;
868 gcc_assert(!(n_counters % 4));
869 n_measures = n_counters / 4;
870 for (i = 0; i < n_measures; i++, counters += 4) {
871 /* last = */
872 gcov_read_counter();
873 value = gcov_read_counter();
874 counter = gcov_read_counter();
875 all = gcov_read_counter();
877 if (counters[1] == value)
878 counters[2] += counter;
879 else if (counter > counters[2]) {
880 counters[1] = value;
881 counters[2] = counter - counters[2];
882 } else
883 counters[2] -= counter;
884 counters[3] += all;
887 #endif /* L_gcov_merge_delta */
889 #ifdef L_gcov_interval_profiler
890 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
891 corresponding counter in COUNTERS. If the VALUE is above or below
892 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
893 instead. */
895 void
896 __gcov_interval_profiler(gcov_type *counters, gcov_type value,
897 int start, unsigned int steps)
899 gcov_type delta = value - start;
900 if (delta < 0)
901 counters[steps + 1]++;
902 else if (delta >= steps)
903 counters[steps]++;
904 else
905 counters[delta]++;
907 #endif
909 #ifdef L_gcov_pow2_profiler
910 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
911 COUNTERS[0] is incremented. */
913 void
914 __gcov_pow2_profiler(gcov_type *counters, gcov_type value)
916 if (value & (value - 1))
917 counters[0]++;
918 else
919 counters[1]++;
921 #endif
923 /* Tries to determine the most common value among its inputs. Checks if the
924 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
925 is incremented. If this is not the case and COUNTERS[1] is not zero,
926 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
927 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
928 function is called more than 50% of the time with one value, this value
929 will be in COUNTERS[0] in the end.
931 In any case, COUNTERS[2] is incremented. */
933 static inline void
934 __gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
936 if (value == counters[0])
937 counters[1]++;
938 else if (counters[1] == 0) {
939 counters[1] = 1;
940 counters[0] = value;
941 } else
942 counters[1]--;
943 counters[2]++;
946 #ifdef L_gcov_one_value_profiler
947 void
948 __gcov_one_value_profiler(gcov_type *counters, gcov_type value)
950 __gcov_one_value_profiler_body(counters, value);
952 #endif
954 #ifdef L_gcov_indirect_call_profiler
956 /* By default, the C++ compiler will use function addresses in the
957 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
958 tells the compiler to use function descriptors instead. The value
959 of this macro says how many words wide the descriptor is (normally 2),
960 but it may be dependent on target flags. Since we do not have access
961 to the target flags here we just check to see if it is set and use
962 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
964 It is assumed that the address of a function descriptor may be treated
965 as a pointer to a function. */
967 #ifdef TARGET_VTABLE_USES_DESCRIPTORS
968 #define VTABLE_USES_DESCRIPTORS 1
969 #else
970 #define VTABLE_USES_DESCRIPTORS 0
971 #endif
973 /* Tries to determine the most common value among its inputs. */
974 void
975 __gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
976 void *cur_func, void *callee_func)
978 /* If the C++ virtual tables contain function descriptors then one
979 * function may have multiple descriptors and we need to dereference
980 * the descriptors to see if they point to the same function.
982 if (cur_func == callee_func
983 || (VTABLE_USES_DESCRIPTORS && callee_func
984 && *(void **) cur_func == *(void **) callee_func))
985 __gcov_one_value_profiler_body(counter, value);
987 #endif
990 #ifdef L_gcov_average_profiler
991 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
992 to saturate up. */
994 void
995 __gcov_average_profiler(gcov_type *counters, gcov_type value)
997 counters[0] += value;
998 counters[1]++;
1000 #endif
1002 #ifdef L_gcov_ior_profiler
1003 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1004 to saturate up. */
1006 void
1007 __gcov_ior_profiler(gcov_type *counters, gcov_type value)
1009 *counters |= value;
1011 #endif
1013 #ifdef L_gcov_fork
1014 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
1015 that they are not counted twice. */
1017 pid_t
1018 __gcov_fork(void)
1020 __gcov_flush();
1021 return fork();
1023 #endif
1025 #ifdef L_gcov_execl
1026 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
1027 that they are not lost. */
1030 __gcov_execl(const char *path, char *arg, ...)
1032 va_list ap, aq;
1033 unsigned int i, length;
1034 char **args;
1036 __gcov_flush();
1038 va_start(ap, arg);
1039 va_copy(aq, ap);
1041 length = 2;
1042 while (va_arg(ap, char *))
1043 length++;
1044 va_end(ap);
1046 args = (char **) alloca(length * sizeof(void *));
1047 args[0] = arg;
1048 for (i = 1; i < length; i++)
1049 args[i] = va_arg(aq, char *);
1050 va_end(aq);
1052 return execv(path, args);
1054 #endif
1056 #ifdef L_gcov_execlp
1057 /* A wrapper for the execlp function. Flushes the accumulated profiling data,
1058 * so that they are not lost.
1062 __gcov_execlp(const char *path, char *arg, ...)
1064 va_list ap, aq;
1065 unsigned int i, length;
1066 char **args;
1068 __gcov_flush();
1070 va_start(ap, arg);
1071 va_copy(aq, ap);
1073 length = 2;
1074 while (va_arg(ap, char *))
1075 length++;
1076 va_end(ap);
1078 args = (char **) alloca(length * sizeof(void *));
1079 args[0] = arg;
1080 for (i = 1; i < length; i++)
1081 args[i] = va_arg(aq, char *);
1082 va_end(aq);
1084 return execvp(path, args);
1086 #endif
1088 #ifdef L_gcov_execle
1089 /* A wrapper for the execle function. Flushes the accumulated profiling data,
1090 * so that they are not lost.
1094 __gcov_execle(const char *path, char *arg, ...)
1096 va_list ap, aq;
1097 unsigned int i, length;
1098 char **args;
1099 char **envp;
1101 __gcov_flush();
1103 va_start(ap, arg);
1104 va_copy(aq, ap);
1106 length = 2;
1107 while (va_arg(ap, char *))
1108 length++;
1109 va_end(ap);
1111 args = (char **) alloca(length * sizeof(void *));
1112 args[0] = arg;
1113 for (i = 1; i < length; i++)
1114 args[i] = va_arg(aq, char *);
1115 envp = va_arg(aq, char **);
1116 va_end(aq);
1118 return execve(path, args, envp);
1120 #endif
1122 #ifdef L_gcov_execv
1123 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
1124 that they are not lost. */
1127 __gcov_execv(const char *path, char *const argv[])
1129 __gcov_flush();
1130 return execv(path, argv);
1132 #endif
1134 #ifdef L_gcov_execvp
1135 /* A wrapper for the execvp function. Flushes the accumulated profiling data,
1136 * so that they are not lost.
1140 __gcov_execvp(const char *path, char *const argv[])
1142 __gcov_flush();
1143 return execvp(path, argv);
1145 #endif
1147 #ifdef L_gcov_execve
1148 /* A wrapper for the execve function. Flushes the accumulated profiling data,
1149 * so that they are not lost.
1153 __gcov_execve(const char *path, char *const argv[], char *const envp[])
1155 __gcov_flush();
1156 return execve(path, argv, envp);
1158 #endif
1159 #endif /* inhibit_libc */