spd/lp5: Add Hynix memory part
[coreboot2.git] / src / lib / libgcov.c
blob61304ff4e320331acb85cf968cbbe76907efdaee
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 #ifdef __COREBOOT__
27 #include <stdlib.h>
28 #include <string.h>
29 #include <commonlib/helpers.h>
30 #include <console/console.h>
31 #include <assert.h>
32 typedef s32 pid_t;
33 #define gcc_assert(x) ASSERT(x)
34 #define fprintf(file, x...) printk(BIOS_ERR, x)
35 #include "gcov-glue.c"
37 /* Define MACROs to be used by coreboot compilation. */
38 # define L_gcov
39 # define L_gcov_interval_profiler
40 # define L_gcov_pow2_profiler
41 # define L_gcov_one_value_profiler
42 # define L_gcov_indirect_call_profiler
43 # define L_gcov_average_profiler
44 # define L_gcov_ior_profiler
46 # define HAVE_CC_TLS 0
47 # define __GCOV_KERNEL__
49 # define IN_LIBGCOV 1
50 # define IN_GCOV 0
51 #else /* __COREBOOT__ */
52 #include "tconfig.h"
53 #include "tsystem.h"
54 #include "coretypes.h"
55 #include "tm.h"
56 #include "libgcc_tm.h"
57 #endif /* __COREBOOT__ */
59 #ifndef __COREBOOT__
60 #if defined(inhibit_libc)
61 #define IN_LIBGCOV (-1)
62 #else
63 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
64 #include <stdio.h>
65 #define IN_LIBGCOV 1
66 #if defined(L_gcov)
67 #define GCOV_LINKAGE /* nothing */
68 #endif
69 #endif
70 #endif /* __COREBOOT__ */
71 #include "gcov-io.h"
73 #if defined(inhibit_libc)
74 /* If libc and its header files are not available, provide dummy functions. */
76 #ifdef L_gcov
77 void __gcov_init(struct gcov_info *p __attribute__((unused))) {}
78 void __gcov_flush(void) {}
79 #endif
81 #ifdef L_gcov_merge_add
82 void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
83 unsigned int n_counters __attribute__((unused))) {}
84 #endif
86 #ifdef L_gcov_merge_single
87 void __gcov_merge_single(gcov_type *counters __attribute__((unused)),
88 unsigned int n_counters __attribute__((unused))) {}
89 #endif
91 #ifdef L_gcov_merge_delta
92 void __gcov_merge_delta(gcov_type *counters __attribute__((unused)),
93 unsigned int n_counters __attribute__((unused))) {}
94 #endif
96 #else
98 #ifndef __COREBOOT__
99 #include <string.h>
100 #if GCOV_LOCKED
101 #include <fcntl.h>
102 #include <errno.h>
103 #include <sys/stat.h>
104 #endif
105 #else
106 void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
107 unsigned int n_counters __attribute__((unused))) {}
108 #endif /* __COREBOOT__ */
110 #ifdef L_gcov
111 #include "gcov-io.c"
113 struct gcov_fn_buffer {
114 struct gcov_fn_buffer *next;
115 unsigned int fn_ix;
116 struct gcov_fn_info info;
117 /* note gcov_fn_info ends in a trailing array. */
120 /* Chain of per-object gcov structures. */
121 static struct gcov_info *gcov_list;
123 /* Size of the longest file name. */
124 static size_t gcov_max_filename = 0;
126 /* Make sure path component of the given FILENAME exists, create
127 missing directories. FILENAME must be writable.
128 Returns zero on success, or -1 if an error occurred. */
130 static int
131 create_file_directory(char *filename)
133 #ifdef __COREBOOT__
134 (void) filename;
135 return 0;
136 #else
137 #if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
138 (void) filename;
139 return -1;
140 #else
141 char *s;
143 s = filename;
145 if (HAS_DRIVE_SPEC(s))
146 s += 2;
147 if (IS_DIR_SEPARATOR(*s))
148 ++s;
149 for (; *s != '\0'; s++)
150 if (IS_DIR_SEPARATOR(*s)) {
151 char sep = *s;
152 *s = '\0';
154 /* Try to make directory if it doesn't already exist. */
155 if (access(filename, F_OK) == -1
156 #ifdef TARGET_POSIX_IO
157 && mkdir(filename, 0755) == -1
158 #else
159 && mkdir(filename) == -1
160 #endif
161 /* The directory might have been made by another
162 * process.
164 && errno != EEXIST) {
165 fprintf(stderr,
166 "profiling:%s:Cannot create directory\n",
167 filename);
168 *s = sep;
169 return -1;
172 *s = sep;
174 return 0;
175 #endif
176 #endif
179 static struct gcov_fn_buffer *
180 free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
181 unsigned int limit)
183 struct gcov_fn_buffer *next;
184 unsigned int ix, n_ctr = 0;
186 if (!buffer)
187 return 0;
188 next = buffer->next;
190 for (ix = 0; ix != limit; ix++)
191 if (gi_ptr->merge[ix])
192 free(buffer->info.ctrs[n_ctr++].values);
193 free(buffer);
194 return next;
197 static struct gcov_fn_buffer **
198 buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr,
199 struct gcov_fn_buffer **end_ptr, unsigned int fn_ix)
201 unsigned int n_ctrs = 0, ix = 0;
202 struct gcov_fn_buffer *fn_buffer;
203 unsigned int len;
205 for (ix = GCOV_COUNTERS; ix--;)
206 if (gi_ptr->merge[ix])
207 n_ctrs++;
209 len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs;
210 fn_buffer = (struct gcov_fn_buffer *)malloc(len);
212 if (!fn_buffer)
213 goto fail;
215 fn_buffer->next = 0;
216 fn_buffer->fn_ix = fn_ix;
217 fn_buffer->info.ident = gcov_read_unsigned();
218 fn_buffer->info.lineno_checksum = gcov_read_unsigned();
219 fn_buffer->info.cfg_checksum = gcov_read_unsigned();
221 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) {
222 gcov_unsigned_t length;
223 gcov_type *values;
225 if (!gi_ptr->merge[ix])
226 continue;
228 if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) {
229 len = 0;
230 goto fail;
233 length = GCOV_TAG_COUNTER_NUM(gcov_read_unsigned());
234 len = length * sizeof(gcov_type);
235 values = (gcov_type *)malloc(len);
236 if (!values)
237 goto fail;
239 fn_buffer->info.ctrs[n_ctrs].num = length;
240 fn_buffer->info.ctrs[n_ctrs].values = values;
242 while (length--)
243 *values++ = gcov_read_counter();
244 n_ctrs++;
247 *end_ptr = fn_buffer;
248 return &fn_buffer->next;
250 fail:
251 fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix,
252 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
254 return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix);
257 /* Add an unsigned value to the current crc */
259 static gcov_unsigned_t
260 crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value)
262 unsigned int ix;
264 for (ix = 32; ix--; value <<= 1) {
265 unsigned int feedback;
267 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
268 crc32 <<= 1;
269 crc32 ^= feedback;
272 return crc32;
275 /* Check if VERSION of the info block PTR matches libgcov one.
276 Return 1 on success, or zero in case of versions mismatch.
277 If FILENAME is not NULL, its value used for reporting purposes
278 instead of value from the info block. */
280 static int
281 gcov_version(struct gcov_info *ptr, gcov_unsigned_t version,
282 const char *filename)
284 if (version != GCOV_VERSION) {
285 char v[4], e[4];
287 GCOV_UNSIGNED2STRING(v, version);
288 GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
290 fprintf(stderr,
291 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
292 filename ? filename : ptr->filename, e, v);
293 return 0;
295 return 1;
298 /* Dump the coverage counts. We merge with existing counts when
299 possible, to avoid growing the .da files ad infinitum. We use this
300 program's checksum to make sure we only accumulate whole program
301 statistics to the correct summary. An object file might be embedded
302 in two separate programs, and we must keep the two program
303 summaries separate. */
305 static void
306 gcov_exit(void)
308 struct gcov_info *gi_ptr;
309 const struct gcov_fn_info *gfi_ptr;
310 struct gcov_summary this_prg; /* summary for program. */
311 struct gcov_summary all_prg; /* summary for all instances of program. */
312 struct gcov_ctr_summary *cs_ptr;
313 const struct gcov_ctr_info *ci_ptr;
314 unsigned int t_ix;
315 int f_ix = 0;
316 gcov_unsigned_t c_num;
317 const char *gcov_prefix;
318 int gcov_prefix_strip = 0;
319 size_t prefix_length;
320 char *gi_filename, *gi_filename_up;
321 gcov_unsigned_t crc32 = 0;
323 memset(&all_prg, 0, sizeof(all_prg));
324 /* Find the totals for this execution. */
325 memset(&this_prg, 0, sizeof(this_prg));
326 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
327 crc32 = crc32_unsigned(crc32, gi_ptr->stamp);
328 crc32 = crc32_unsigned(crc32, gi_ptr->n_functions);
330 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
331 f_ix++) {
332 gfi_ptr = gi_ptr->functions[f_ix];
334 if (gfi_ptr && gfi_ptr->key != gi_ptr)
335 gfi_ptr = 0;
337 crc32 = crc32_unsigned(crc32, gfi_ptr
338 ? gfi_ptr->cfg_checksum : 0);
339 crc32 = crc32_unsigned(crc32,
340 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
341 if (!gfi_ptr)
342 continue;
344 ci_ptr = gfi_ptr->ctrs;
345 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) {
346 if (!gi_ptr->merge[t_ix])
347 continue;
349 cs_ptr = &this_prg.ctrs[t_ix];
350 cs_ptr->num += ci_ptr->num;
351 crc32 = crc32_unsigned(crc32, ci_ptr->num);
353 for (c_num = 0; c_num < ci_ptr->num; c_num++) {
354 cs_ptr->sum_all +=
355 ci_ptr->values[c_num];
356 if (cs_ptr->run_max
357 < ci_ptr->values[c_num])
358 cs_ptr->run_max =
359 ci_ptr->values[c_num];
361 ci_ptr++;
366 #ifndef __COREBOOT__
368 /* Check if the level of dirs to strip off specified. */
369 char *tmp = getenv("GCOV_PREFIX_STRIP");
370 if (tmp) {
371 gcov_prefix_strip = atoi(tmp);
372 /* Do not consider negative values. */
373 if (gcov_prefix_strip < 0)
374 gcov_prefix_strip = 0;
378 /* Get file name relocation prefix. Non-absolute values are ignored. */
379 gcov_prefix = getenv("GCOV_PREFIX");
380 if (gcov_prefix) {
381 prefix_length = strlen(gcov_prefix);
383 /* Remove an unnecessary trailing '/' */
384 if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1]))
385 prefix_length--;
386 } else
387 #endif
388 prefix_length = 0;
390 /* If no prefix was specified and a prefix strip, then we assume
391 relative. */
392 if (gcov_prefix_strip != 0 && prefix_length == 0) {
393 gcov_prefix = ".";
394 prefix_length = 1;
396 /* Allocate and initialize the filename scratch space plus one. */
397 gi_filename = (char *) alloca(prefix_length + gcov_max_filename + 2);
398 if (prefix_length)
399 memcpy(gi_filename, gcov_prefix, prefix_length);
400 gi_filename_up = gi_filename + prefix_length;
402 /* Now merge each file. */
403 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
404 unsigned int n_counts;
405 struct gcov_summary prg; /* summary for this object over all
406 program. */
407 struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
408 int error = 0;
409 gcov_unsigned_t tag, length;
410 gcov_position_t summary_pos = 0;
411 gcov_position_t eof_pos = 0;
412 const char *fname, *s;
413 struct gcov_fn_buffer *fn_buffer = NULL;
414 struct gcov_fn_buffer **fn_tail = &fn_buffer;
416 fname = gi_ptr->filename;
418 /* Avoid to add multiple drive letters into combined path. */
419 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
420 fname += 2;
422 /* Build relocated filename, stripping off leading
423 * directories from the initial filename if requested.
425 if (gcov_prefix_strip > 0) {
426 int level = 0;
428 s = fname;
429 if (IS_DIR_SEPARATOR(*s))
430 ++s;
432 /* Skip selected directory levels. */
433 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
434 if (IS_DIR_SEPARATOR(*s)) {
435 fname = s;
436 level++;
440 /* Update complete filename with stripped original. */
441 if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) {
442 /* If prefix is given, add directory separator.
444 strcpy(gi_filename_up, "/");
445 strcpy(gi_filename_up + 1, fname);
446 } else
447 strcpy(gi_filename_up, fname);
449 if (!gcov_open(gi_filename)) {
450 /* Open failed likely due to missed directory.
451 * Create directory and retry to open file.
453 if (create_file_directory(gi_filename)) {
454 fprintf(stderr, "profiling:%s:Skip\n",
455 gi_filename);
456 continue;
458 if (!gcov_open(gi_filename)) {
459 fprintf(stderr,
460 "profiling:%s:Cannot open\n",
461 gi_filename);
462 continue;
466 tag = gcov_read_unsigned();
467 if (tag) {
468 /* Merge data from file. */
469 if (tag != GCOV_DATA_MAGIC) {
470 fprintf(stderr,
471 "profiling:%s:Not a gcov data file\n",
472 gi_filename);
473 goto read_fatal;
475 length = gcov_read_unsigned();
476 if (!gcov_version(gi_ptr, length, gi_filename))
477 goto read_fatal;
479 length = gcov_read_unsigned();
480 if (length != gi_ptr->stamp)
481 /* Read from a different compilation.
482 * Overwrite the file.
484 goto rewrite;
486 /* Look for program summary. */
487 for (f_ix = 0;;) {
488 struct gcov_summary tmp;
490 eof_pos = gcov_position();
491 tag = gcov_read_unsigned();
492 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
493 break;
495 f_ix--;
496 length = gcov_read_unsigned();
497 if (length != GCOV_TAG_SUMMARY_LENGTH)
498 goto read_mismatch;
499 gcov_read_summary(&tmp);
500 error = gcov_is_error();
501 if (error)
502 goto read_error;
503 if (summary_pos
504 || tmp.checksum != crc32)
505 goto next_summary;
507 for (t_ix = 0; t_ix !=
508 GCOV_COUNTERS_SUMMABLE; t_ix++)
509 if (tmp.ctrs[t_ix].num !=
510 this_prg.ctrs[t_ix].num)
511 goto next_summary;
512 prg = tmp;
513 summary_pos = eof_pos;
515 next_summary:;
518 /* Merge execution counts for each function. */
519 for (f_ix = 0; (unsigned int)f_ix !=
520 gi_ptr->n_functions;
521 f_ix++, tag = gcov_read_unsigned()) {
522 gfi_ptr = gi_ptr->functions[f_ix];
524 if (tag != GCOV_TAG_FUNCTION)
525 goto read_mismatch;
527 length = gcov_read_unsigned();
528 if (!length)
529 /* This function did not appear
530 * in the other program. We
531 * have nothing to merge.
533 continue;
535 if (length != GCOV_TAG_FUNCTION_LENGTH)
536 goto read_mismatch;
538 if (!gfi_ptr || gfi_ptr->key !=
539 gi_ptr) {
540 /* This function appears in the
541 * other program. We need to
542 * buffer the information in
543 * order to write it back out --
544 * we'll be inserting data
545 * before this point, so cannot
546 * simply keep the data in the
547 * file.
549 fn_tail = buffer_fn_data(
550 gi_filename, gi_ptr,
551 fn_tail, f_ix);
552 if (!fn_tail)
553 goto read_mismatch;
554 continue;
557 length = gcov_read_unsigned();
558 if (length != gfi_ptr->ident)
559 goto read_mismatch;
561 length = gcov_read_unsigned();
562 if (length != gfi_ptr->lineno_checksum)
563 goto read_mismatch;
565 length = gcov_read_unsigned();
566 if (length != gfi_ptr->cfg_checksum)
567 goto read_mismatch;
569 ci_ptr = gfi_ptr->ctrs;
570 for (t_ix = 0; t_ix < GCOV_COUNTERS;
571 t_ix++) {
572 gcov_merge_fn merge =
573 gi_ptr->merge[t_ix];
575 if (!merge)
576 continue;
578 tag = gcov_read_unsigned();
579 length = gcov_read_unsigned();
580 if (tag != GCOV_TAG_FOR_COUNTER(
581 t_ix) || length !=
582 GCOV_TAG_COUNTER_LENGTH(
583 ci_ptr->num))
584 goto read_mismatch;
585 (*merge)(ci_ptr->values,
586 ci_ptr->num);
587 ci_ptr++;
589 error = gcov_is_error();
590 if (error)
591 goto read_error;
594 if (tag) {
595 read_mismatch:;
596 fprintf(stderr,
597 "profiling:%s:Merge mismatch for %s %u\n",
598 gi_filename, f_ix >= 0 ?
599 "function" : "summary",
600 f_ix < 0 ? -1 - f_ix : f_ix);
601 goto read_fatal;
604 goto rewrite;
606 read_error:;
607 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
608 error < 0 ? "Overflow" : "Error");
610 goto read_fatal;
612 rewrite:;
613 gcov_rewrite();
614 if (!summary_pos) {
615 memset(&prg, 0, sizeof(prg));
616 summary_pos = eof_pos;
619 /* Merge the summaries. */
620 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) {
621 cs_prg = &prg.ctrs[t_ix];
622 cs_tprg = &this_prg.ctrs[t_ix];
623 cs_all = &all_prg.ctrs[t_ix];
625 if (gi_ptr->merge[t_ix]) {
626 if (!cs_prg->runs++)
627 cs_prg->num = cs_tprg->num;
628 cs_prg->sum_all += cs_tprg->sum_all;
629 if (cs_prg->run_max < cs_tprg->run_max)
630 cs_prg->run_max = cs_tprg->run_max;
631 cs_prg->sum_max += cs_tprg->run_max;
632 } else if (cs_prg->runs)
633 goto read_mismatch;
635 if (!cs_all->runs && cs_prg->runs)
636 memcpy(cs_all, cs_prg, sizeof(*cs_all));
637 else if (!all_prg.checksum
638 && (!GCOV_LOCKED
639 || cs_all->runs == cs_prg->runs)
640 && memcmp(cs_all, cs_prg, sizeof(*cs_all))) {
641 fprintf(stderr,
642 "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
643 gi_filename, GCOV_LOCKED ? "" :
644 " or concurrently updated without locking support");
645 all_prg.checksum = ~0u;
649 prg.checksum = crc32;
651 /* Write out the data. */
652 if (!eof_pos) {
653 gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
654 gcov_write_unsigned(gi_ptr->stamp);
657 if (summary_pos)
658 gcov_seek(summary_pos);
660 /* Generate whole program statistics. */
661 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
663 if (summary_pos < eof_pos)
664 gcov_seek(eof_pos);
666 /* Write execution counts for each function. */
667 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
668 f_ix++) {
669 unsigned int buffered = 0;
671 if (fn_buffer && fn_buffer->fn_ix
672 == (unsigned int)f_ix) {
673 /* Buffered data from another program. */
674 buffered = 1;
675 gfi_ptr = &fn_buffer->info;
676 length = GCOV_TAG_FUNCTION_LENGTH;
677 } else {
678 gfi_ptr = gi_ptr->functions[f_ix];
679 if (gfi_ptr && gfi_ptr->key == gi_ptr)
680 length = GCOV_TAG_FUNCTION_LENGTH;
681 else
682 length = 0;
685 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
686 if (!length)
687 continue;
689 gcov_write_unsigned(gfi_ptr->ident);
690 gcov_write_unsigned(gfi_ptr->lineno_checksum);
691 gcov_write_unsigned(gfi_ptr->cfg_checksum);
693 ci_ptr = gfi_ptr->ctrs;
694 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) {
695 if (!gi_ptr->merge[t_ix])
696 continue;
698 n_counts = ci_ptr->num;
699 gcov_write_tag_length(
700 GCOV_TAG_FOR_COUNTER(t_ix),
701 GCOV_TAG_COUNTER_LENGTH(n_counts));
702 gcov_type *c_ptr = ci_ptr->values;
703 while (n_counts--)
704 gcov_write_counter(*c_ptr++);
705 ci_ptr++;
707 if (buffered)
708 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
709 GCOV_COUNTERS);
712 gcov_write_unsigned(0);
714 read_fatal:;
715 while (fn_buffer)
716 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
717 GCOV_COUNTERS);
719 error = gcov_close();
720 if (error)
721 fprintf(stderr, error < 0 ?
722 "profiling:%s:Overflow writing\n" :
723 "profiling:%s:Error writing\n",
724 gi_filename);
728 /* Add a new object file onto the bb chain. Invoked automatically
729 when running an object file's global ctors. */
731 void
732 __gcov_init(struct gcov_info *info)
734 if (!info->version || !info->n_functions)
735 return;
736 if (gcov_version(info, info->version, 0)) {
737 size_t filename_length = strlen(info->filename);
739 /* Refresh the longest file name information */
740 if (filename_length > gcov_max_filename)
741 gcov_max_filename = filename_length;
743 #ifndef __COREBOOT__
744 if (!gcov_list)
745 atexit(gcov_exit);
746 #endif
748 info->next = gcov_list;
749 gcov_list = info;
751 info->version = 0;
754 /* Called before fork or exec - write out profile information gathered so
755 far and reset it to zero. This avoids duplication or loss of the
756 profile information gathered so far. */
758 void
759 __gcov_flush(void)
761 const struct gcov_info *gi_ptr;
763 gcov_exit();
764 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
765 unsigned int f_ix;
767 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) {
768 unsigned int t_ix;
769 const struct gcov_fn_info *gfi_ptr =
770 gi_ptr->functions[f_ix];
772 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
773 continue;
774 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
775 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) {
776 if (!gi_ptr->merge[t_ix])
777 continue;
779 memset(ci_ptr->values, 0,
780 sizeof(gcov_type) * ci_ptr->num);
781 ci_ptr++;
787 #endif /* L_gcov */
789 #ifdef L_gcov_merge_add
790 /* The profile merging function that just adds the counters. It is given
791 an array COUNTERS of N_COUNTERS old counters and it reads the same number
792 of counters from the gcov file. */
793 void
794 __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
796 for (; n_counters; counters++, n_counters--)
797 *counters += gcov_read_counter();
799 #endif /* L_gcov_merge_add */
801 #ifdef L_gcov_merge_ior
802 /* The profile merging function that just adds the counters. It is given
803 an array COUNTERS of N_COUNTERS old counters and it reads the same number
804 of counters from the gcov file. */
805 void
806 __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
808 for (; n_counters; counters++, n_counters--)
809 *counters |= gcov_read_counter();
811 #endif
813 #ifdef L_gcov_merge_single
814 /* The profile merging function for choosing the most common value.
815 * It is given an array COUNTERS of N_COUNTERS old counters and it
816 * reads the same number of counters from the gcov file. The counters
817 * are split into 3-tuples where the members of the tuple have
818 * meanings:
820 * -- the stored candidate on the most common value of the measured entity
821 * -- counter
822 * -- total number of evaluations of the value
824 void
825 __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
827 unsigned int i, n_measures;
828 gcov_type value, counter, all;
830 gcc_assert(!(n_counters % 3));
831 n_measures = n_counters / 3;
832 for (i = 0; i < n_measures; i++, counters += 3) {
833 value = gcov_read_counter();
834 counter = gcov_read_counter();
835 all = gcov_read_counter();
837 if (counters[0] == value)
838 counters[1] += counter;
839 else if (counter > counters[1]) {
840 counters[0] = value;
841 counters[1] = counter - counters[1];
842 } else
843 counters[1] -= counter;
844 counters[2] += all;
847 #endif /* L_gcov_merge_single */
849 #ifdef L_gcov_merge_delta
850 /* The profile merging function for choosing the most common
851 * difference between two consecutive evaluations of the value. It is
852 * given an array COUNTERS of N_COUNTERS old counters and it reads the
853 * same number of counters from the gcov file. The counters are split
854 * into 4-tuples where the members of the tuple have meanings:
856 * -- the last value of the measured entity
857 * -- the stored candidate on the most common difference
858 * -- counter
859 * -- total number of evaluations of the value
861 void
862 __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
864 unsigned int i, n_measures;
865 gcov_type value, counter, all;
867 gcc_assert(!(n_counters % 4));
868 n_measures = n_counters / 4;
869 for (i = 0; i < n_measures; i++, counters += 4) {
870 /* last = */
871 gcov_read_counter();
872 value = gcov_read_counter();
873 counter = gcov_read_counter();
874 all = gcov_read_counter();
876 if (counters[1] == value)
877 counters[2] += counter;
878 else if (counter > counters[2]) {
879 counters[1] = value;
880 counters[2] = counter - counters[2];
881 } else
882 counters[2] -= counter;
883 counters[3] += all;
886 #endif /* L_gcov_merge_delta */
888 #ifdef L_gcov_interval_profiler
889 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
890 corresponding counter in COUNTERS. If the VALUE is above or below
891 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
892 instead. */
894 void
895 __gcov_interval_profiler(gcov_type *counters, gcov_type value,
896 int start, unsigned int steps)
898 gcov_type delta = value - start;
899 if (delta < 0)
900 counters[steps + 1]++;
901 else if (delta >= steps)
902 counters[steps]++;
903 else
904 counters[delta]++;
906 #endif
908 #ifdef L_gcov_pow2_profiler
909 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
910 COUNTERS[0] is incremented. */
912 void
913 __gcov_pow2_profiler(gcov_type *counters, gcov_type value)
915 if (value & (value - 1))
916 counters[0]++;
917 else
918 counters[1]++;
920 #endif
922 /* Tries to determine the most common value among its inputs. Checks if the
923 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
924 is incremented. If this is not the case and COUNTERS[1] is not zero,
925 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
926 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
927 function is called more than 50% of the time with one value, this value
928 will be in COUNTERS[0] in the end.
930 In any case, COUNTERS[2] is incremented. */
932 static inline void
933 __gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
935 if (value == counters[0])
936 counters[1]++;
937 else if (counters[1] == 0) {
938 counters[1] = 1;
939 counters[0] = value;
940 } else
941 counters[1]--;
942 counters[2]++;
945 #ifdef L_gcov_one_value_profiler
946 void
947 __gcov_one_value_profiler(gcov_type *counters, gcov_type value)
949 __gcov_one_value_profiler_body(counters, value);
951 #endif
953 #ifdef L_gcov_indirect_call_profiler
955 /* By default, the C++ compiler will use function addresses in the
956 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
957 tells the compiler to use function descriptors instead. The value
958 of this macro says how many words wide the descriptor is (normally 2),
959 but it may be dependent on target flags. Since we do not have access
960 to the target flags here we just check to see if it is set and use
961 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
963 It is assumed that the address of a function descriptor may be treated
964 as a pointer to a function. */
966 #ifdef TARGET_VTABLE_USES_DESCRIPTORS
967 #define VTABLE_USES_DESCRIPTORS 1
968 #else
969 #define VTABLE_USES_DESCRIPTORS 0
970 #endif
972 /* Tries to determine the most common value among its inputs. */
973 void
974 __gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
975 void *cur_func, void *callee_func)
977 /* If the C++ virtual tables contain function descriptors then one
978 * function may have multiple descriptors and we need to dereference
979 * the descriptors to see if they point to the same function.
981 if (cur_func == callee_func
982 || (VTABLE_USES_DESCRIPTORS && callee_func
983 && *(void **) cur_func == *(void **) callee_func))
984 __gcov_one_value_profiler_body(counter, value);
986 #endif
989 #ifdef L_gcov_average_profiler
990 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
991 to saturate up. */
993 void
994 __gcov_average_profiler(gcov_type *counters, gcov_type value)
996 counters[0] += value;
997 counters[1]++;
999 #endif
1001 #ifdef L_gcov_ior_profiler
1002 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1003 to saturate up. */
1005 void
1006 __gcov_ior_profiler(gcov_type *counters, gcov_type value)
1008 *counters |= value;
1010 #endif
1012 #ifdef L_gcov_fork
1013 /* A wrapper for the fork function. Flushes the accumulated profiling data, so
1014 that they are not counted twice. */
1016 pid_t
1017 __gcov_fork(void)
1019 __gcov_flush();
1020 return fork();
1022 #endif
1024 #ifdef L_gcov_execl
1025 /* A wrapper for the execl function. Flushes the accumulated profiling data, so
1026 that they are not lost. */
1029 __gcov_execl(const char *path, char *arg, ...)
1031 va_list ap, aq;
1032 unsigned int i, length;
1033 char **args;
1035 __gcov_flush();
1037 va_start(ap, arg);
1038 va_copy(aq, ap);
1040 length = 2;
1041 while (va_arg(ap, char *))
1042 length++;
1043 va_end(ap);
1045 args = (char **) alloca(length * sizeof(void *));
1046 args[0] = arg;
1047 for (i = 1; i < length; i++)
1048 args[i] = va_arg(aq, char *);
1049 va_end(aq);
1051 return execv(path, args);
1053 #endif
1055 #ifdef L_gcov_execlp
1056 /* A wrapper for the execlp function. Flushes the accumulated profiling data,
1057 * so that they are not lost.
1061 __gcov_execlp(const char *path, char *arg, ...)
1063 va_list ap, aq;
1064 unsigned int i, length;
1065 char **args;
1067 __gcov_flush();
1069 va_start(ap, arg);
1070 va_copy(aq, ap);
1072 length = 2;
1073 while (va_arg(ap, char *))
1074 length++;
1075 va_end(ap);
1077 args = (char **) alloca(length * sizeof(void *));
1078 args[0] = arg;
1079 for (i = 1; i < length; i++)
1080 args[i] = va_arg(aq, char *);
1081 va_end(aq);
1083 return execvp(path, args);
1085 #endif
1087 #ifdef L_gcov_execle
1088 /* A wrapper for the execle function. Flushes the accumulated profiling data,
1089 * so that they are not lost.
1093 __gcov_execle(const char *path, char *arg, ...)
1095 va_list ap, aq;
1096 unsigned int i, length;
1097 char **args;
1098 char **envp;
1100 __gcov_flush();
1102 va_start(ap, arg);
1103 va_copy(aq, ap);
1105 length = 2;
1106 while (va_arg(ap, char *))
1107 length++;
1108 va_end(ap);
1110 args = (char **) alloca(length * sizeof(void *));
1111 args[0] = arg;
1112 for (i = 1; i < length; i++)
1113 args[i] = va_arg(aq, char *);
1114 envp = va_arg(aq, char **);
1115 va_end(aq);
1117 return execve(path, args, envp);
1119 #endif
1121 #ifdef L_gcov_execv
1122 /* A wrapper for the execv function. Flushes the accumulated profiling data, so
1123 that they are not lost. */
1126 __gcov_execv(const char *path, char *const argv[])
1128 __gcov_flush();
1129 return execv(path, argv);
1131 #endif
1133 #ifdef L_gcov_execvp
1134 /* A wrapper for the execvp function. Flushes the accumulated profiling data,
1135 * so that they are not lost.
1139 __gcov_execvp(const char *path, char *const argv[])
1141 __gcov_flush();
1142 return execvp(path, argv);
1144 #endif
1146 #ifdef L_gcov_execve
1147 /* A wrapper for the execve function. Flushes the accumulated profiling data,
1148 * so that they are not lost.
1152 __gcov_execve(const char *path, char *const argv[], char *const envp[])
1154 __gcov_flush();
1155 return execve(path, argv, envp);
1157 #endif
1158 #endif /* inhibit_libc */