blob: 22a83c164fdde89a4d8be27e975838a408649df2 [file] [log] [blame]
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001/* 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, 2011
5 Free Software Foundation, Inc.
6
7This file is part of GCC.
8
9GCC is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
11Software Foundation; either version 3, or (at your option) any later
12version.
13
14GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
18
19Under Section 7 of GPL version 3, you are granted additional
20permissions described in the GCC Runtime Library Exception, version
213.1, as published by the Free Software Foundation.
Patrick Georgia73b9312015-10-31 11:55:10 +010022*/
Stefan Reinauerd37ab452012-12-18 16:23:28 -080023
24#define __COREBOOT__
25#ifdef __COREBOOT__
26#include <stdlib.h>
27#include <string.h>
28#include <console/console.h>
29#include <assert.h>
30typedef s32 pid_t;
31#define gcc_assert(x) ASSERT(x)
32#define fprintf(file, x...) printk(BIOS_ERR, x)
Lee Leahy38768c32017-03-09 14:07:18 -080033#define alloca(size) __builtin_alloca(size)
Stefan Reinauerd37ab452012-12-18 16:23:28 -080034#include "gcov-glue.c"
35
36/* Define MACROs to be used by coreboot compilation. */
37# define L_gcov
38# define L_gcov_interval_profiler
39# define L_gcov_pow2_profiler
40# define L_gcov_one_value_profiler
41# define L_gcov_indirect_call_profiler
42# define L_gcov_average_profiler
43# define L_gcov_ior_profiler
44
45# define HAVE_CC_TLS 0
46# define __GCOV_KERNEL__
47
48# define IN_LIBGCOV 1
49# define IN_GCOV 0
50#else /* __COREBOOT__ */
51#include "tconfig.h"
52#include "tsystem.h"
53#include "coretypes.h"
54#include "tm.h"
55#include "libgcc_tm.h"
56#endif /* __COREBOOT__ */
57
58#ifndef __COREBOOT__
59#if defined(inhibit_libc)
60#define IN_LIBGCOV (-1)
61#else
62#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
63#include <stdio.h>
64#define IN_LIBGCOV 1
65#if defined(L_gcov)
66#define GCOV_LINKAGE /* nothing */
67#endif
68#endif
69#endif /* __COREBOOT__ */
70#include "gcov-io.h"
71
72#if defined(inhibit_libc)
73/* If libc and its header files are not available, provide dummy functions. */
74
75#ifdef L_gcov
Lee Leahy38768c32017-03-09 14:07:18 -080076void __gcov_init(struct gcov_info *p __attribute__ ((unused))) {}
77void __gcov_flush(void) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080078#endif
79
80#ifdef L_gcov_merge_add
Lee Leahy38768c32017-03-09 14:07:18 -080081void __gcov_merge_add(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080082 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080083#endif
84
85#ifdef L_gcov_merge_single
Lee Leahy38768c32017-03-09 14:07:18 -080086void __gcov_merge_single(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080087 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080088#endif
89
90#ifdef L_gcov_merge_delta
Lee Leahy38768c32017-03-09 14:07:18 -080091void __gcov_merge_delta(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080092 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080093#endif
94
95#else
96
97#ifndef __COREBOOT__
98#include <string.h>
99#if GCOV_LOCKED
100#include <fcntl.h>
101#include <errno.h>
102#include <sys/stat.h>
103#endif
104#else
105void __gcov_merge_add(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -0800106 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800107#endif /* __COREBOOT__ */
108
109#ifdef L_gcov
110#include "gcov-io.c"
111
112struct gcov_fn_buffer
113{
Lee Leahye20a3192017-03-09 16:21:34 -0800114 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. */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800118};
119
120/* Chain of per-object gcov structures. */
121static struct gcov_info *gcov_list;
122
123/* Size of the longest file name. */
124static size_t gcov_max_filename = 0;
125
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. */
129
130static int
Lee Leahy38768c32017-03-09 14:07:18 -0800131create_file_directory(char *filename)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800132{
133#ifdef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800134 (void) filename;
135 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800136#else
137#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
Lee Leahye20a3192017-03-09 16:21:34 -0800138 (void) filename;
139 return -1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800140#else
Lee Leahye20a3192017-03-09 16:21:34 -0800141 char *s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800142
Lee Leahye20a3192017-03-09 16:21:34 -0800143 s = filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800144
Lee Leahye20a3192017-03-09 16:21:34 -0800145 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';
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800153
Lee Leahye20a3192017-03-09 16:21:34 -0800154 /* Try to make directory if it doesn't already exist. */
155 if (access(filename, F_OK) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800156#ifdef TARGET_POSIX_IO
Lee Leahye20a3192017-03-09 16:21:34 -0800157 && mkdir(filename, 0755) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800158#else
Lee Leahye20a3192017-03-09 16:21:34 -0800159 && mkdir(filename) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800160#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800161 /* The directory might have been made by another
162 * process.
163 */
164 && errno != EEXIST) {
165 fprintf(stderr,
166 "profiling:%s:Cannot create directory\n",
167 filename);
168 *s = sep;
169 return -1;
170 };
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800171
Lee Leahye20a3192017-03-09 16:21:34 -0800172 *s = sep;
173 };
174 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800175#endif
176#endif
177}
178
179static struct gcov_fn_buffer *
Lee Leahy38768c32017-03-09 14:07:18 -0800180free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
Lee Leahy75b85992017-03-08 16:34:12 -0800181 unsigned int limit)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800182{
Lee Leahye20a3192017-03-09 16:21:34 -0800183 struct gcov_fn_buffer *next;
184 unsigned int ix, n_ctr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800185
Lee Leahye20a3192017-03-09 16:21:34 -0800186 if (!buffer)
187 return 0;
188 next = buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800189
Lee Leahye20a3192017-03-09 16:21:34 -0800190 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800195}
196
197static struct gcov_fn_buffer **
Lee Leahy38768c32017-03-09 14:07:18 -0800198buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr,
Lee Leahy75b85992017-03-08 16:34:12 -0800199 struct gcov_fn_buffer **end_ptr, unsigned int fn_ix)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800200{
Lee Leahye20a3192017-03-09 16:21:34 -0800201 unsigned int n_ctrs = 0, ix = 0;
202 struct gcov_fn_buffer *fn_buffer;
203 unsigned int len;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800204
Lee Leahye20a3192017-03-09 16:21:34 -0800205 for (ix = GCOV_COUNTERS; ix--;)
206 if (gi_ptr->merge[ix])
207 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800208
Lee Leahye20a3192017-03-09 16:21:34 -0800209 len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs;
210 fn_buffer = (struct gcov_fn_buffer *)malloc(len);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800211
Lee Leahye20a3192017-03-09 16:21:34 -0800212 if (!fn_buffer)
213 goto fail;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800214
Lee Leahye20a3192017-03-09 16:21:34 -0800215 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();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800220
Lee Leahye20a3192017-03-09 16:21:34 -0800221 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) {
222 gcov_unsigned_t length;
223 gcov_type *values;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800224
Lee Leahye20a3192017-03-09 16:21:34 -0800225 if (!gi_ptr->merge[ix])
226 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800227
Lee Leahye20a3192017-03-09 16:21:34 -0800228 if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) {
229 len = 0;
230 goto fail;
231 }
232
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;
238
239 fn_buffer->info.ctrs[n_ctrs].num = length;
240 fn_buffer->info.ctrs[n_ctrs].values = values;
241
242 while (length--)
243 *values++ = gcov_read_counter();
244 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800245 }
246
Lee Leahye20a3192017-03-09 16:21:34 -0800247 *end_ptr = fn_buffer;
248 return &fn_buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800249
250fail:
Lee Leahy35af5c42017-03-09 17:35:28 -0800251 fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix,
Lee Leahye20a3192017-03-09 16:21:34 -0800252 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800253
Lee Leahye20a3192017-03-09 16:21:34 -0800254 return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800255}
256
257/* Add an unsigned value to the current crc */
258
259static gcov_unsigned_t
Lee Leahy38768c32017-03-09 14:07:18 -0800260crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800261{
Lee Leahye20a3192017-03-09 16:21:34 -0800262 unsigned int ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800263
Lee Leahye20a3192017-03-09 16:21:34 -0800264 for (ix = 32; ix--; value <<= 1) {
265 unsigned int feedback;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800266
Lee Leahye20a3192017-03-09 16:21:34 -0800267 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
268 crc32 <<= 1;
269 crc32 ^= feedback;
270 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800271
Lee Leahye20a3192017-03-09 16:21:34 -0800272 return crc32;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800273}
274
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. */
279
280static int
Lee Leahy38768c32017-03-09 14:07:18 -0800281gcov_version(struct gcov_info *ptr, gcov_unsigned_t version,
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800282 const char *filename)
283{
Lee Leahye20a3192017-03-09 16:21:34 -0800284 if (version != GCOV_VERSION) {
285 char v[4], e[4];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800286
Lee Leahye20a3192017-03-09 16:21:34 -0800287 GCOV_UNSIGNED2STRING(v, version);
288 GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800289
Lee Leahye20a3192017-03-09 16:21:34 -0800290 fprintf(stderr,
291 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
Lee Leahy35af5c42017-03-09 17:35:28 -0800292 filename ? filename : ptr->filename, e, v);
Lee Leahye20a3192017-03-09 16:21:34 -0800293 return 0;
294 }
295 return 1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800296}
297
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. */
304
305static void
Lee Leahy38768c32017-03-09 14:07:18 -0800306gcov_exit(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800307{
Lee Leahye20a3192017-03-09 16:21:34 -0800308 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800322
Lee Leahye20a3192017-03-09 16:21:34 -0800323 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);
Kyösti Mälkkiecd84242013-09-13 07:57:49 +0300329
Lee Leahye20a3192017-03-09 16:21:34 -0800330 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
331 f_ix++) {
332 gfi_ptr = gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800333
Lee Leahye20a3192017-03-09 16:21:34 -0800334 if (gfi_ptr && gfi_ptr->key != gi_ptr)
335 gfi_ptr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800336
Lee Leahye20a3192017-03-09 16:21:34 -0800337 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800343
Lee Leahye20a3192017-03-09 16:21:34 -0800344 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800348
Lee Leahye20a3192017-03-09 16:21:34 -0800349 cs_ptr = &this_prg.ctrs[t_ix];
350 cs_ptr->num += ci_ptr->num;
351 crc32 = crc32_unsigned(crc32, ci_ptr->num);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800352
Lee Leahye20a3192017-03-09 16:21:34 -0800353 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];
360 }
361 ci_ptr++;
362 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800363 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800364 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800365
366#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800367 {
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;
375 }
376 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800377
Lee Leahye20a3192017-03-09 16:21:34 -0800378 /* 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);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800382
Lee Leahye20a3192017-03-09 16:21:34 -0800383 /* Remove an unnecessary trailing '/' */
384 if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1]))
385 prefix_length--;
386 } else
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800387#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800388 prefix_length = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800389
Lee Leahye20a3192017-03-09 16:21:34 -0800390 /* 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800395 }
Lee Leahye20a3192017-03-09 16:21:34 -0800396 /* 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800401
Lee Leahye20a3192017-03-09 16:21:34 -0800402 /* 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 = 0;
414 struct gcov_fn_buffer **fn_tail = &fn_buffer;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800415
Lee Leahye20a3192017-03-09 16:21:34 -0800416 fname = gi_ptr->filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800417
Lee Leahye20a3192017-03-09 16:21:34 -0800418 /* Avoid to add multiple drive letters into combined path. */
419 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
420 fname += 2;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800421
Lee Leahye20a3192017-03-09 16:21:34 -0800422 /* Build relocated filename, stripping off leading
423 * directories from the initial filename if requested.
424 */
425 if (gcov_prefix_strip > 0) {
426 int level = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800427
Lee Leahye20a3192017-03-09 16:21:34 -0800428 s = fname;
429 if (IS_DIR_SEPARATOR(*s))
430 ++s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800431
Lee Leahye20a3192017-03-09 16:21:34 -0800432 /* Skip selected directory levels. */
433 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
434 if (IS_DIR_SEPARATOR(*s)) {
435 fname = s;
436 level++;
437 }
438 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800439
Lee Leahye20a3192017-03-09 16:21:34 -0800440 /* Update complete filename with stripped original. */
441 if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) {
442 /* If prefix is given, add directory separator.
443 */
444 strcpy(gi_filename_up, "/");
445 strcpy(gi_filename_up + 1, fname);
446 } else
447 strcpy(gi_filename_up, fname);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800448
Lee Leahye20a3192017-03-09 16:21:34 -0800449 if (!gcov_open(gi_filename)) {
450 /* Open failed likely due to missed directory.
451 * Create directory and retry to open file.
452 */
453 if (create_file_directory(gi_filename)) {
454 fprintf(stderr, "profiling:%s:Skip\n",
455 gi_filename);
456 continue;
457 }
458 if (!gcov_open(gi_filename)) {
459 fprintf(stderr,
460 "profiling:%s:Cannot open\n",
461 gi_filename);
462 continue;
463 }
464 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800465
Lee Leahye20a3192017-03-09 16:21:34 -0800466 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;
474 }
475 length = gcov_read_unsigned();
476 if (!gcov_version(gi_ptr, length, gi_filename))
477 goto read_fatal;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800478
Lee Leahye20a3192017-03-09 16:21:34 -0800479 length = gcov_read_unsigned();
480 if (length != gi_ptr->stamp)
481 /* Read from a different compilation.
482 * Overwrite the file.
483 */
484 goto rewrite;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800485
Lee Leahye20a3192017-03-09 16:21:34 -0800486 /* Look for program summary. */
487 for (f_ix = 0;;) {
488 struct gcov_summary tmp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800489
Lee Leahye20a3192017-03-09 16:21:34 -0800490 eof_pos = gcov_position();
491 tag = gcov_read_unsigned();
492 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
493 break;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800494
Lee Leahye20a3192017-03-09 16:21:34 -0800495 f_ix--;
496 length = gcov_read_unsigned();
497 if (length != GCOV_TAG_SUMMARY_LENGTH)
498 goto read_mismatch;
499 gcov_read_summary(&tmp);
500 if ((error = gcov_is_error()))
501 goto read_error;
502 if (summary_pos
503 || tmp.checksum != crc32)
504 goto next_summary;
505
506 for (t_ix = 0; t_ix !=
507 GCOV_COUNTERS_SUMMABLE; t_ix++)
508 if (tmp.ctrs[t_ix].num !=
509 this_prg.ctrs[t_ix].num)
510 goto next_summary;
511 prg = tmp;
512 summary_pos = eof_pos;
513
514 next_summary:;
515 }
516
517 /* Merge execution counts for each function. */
518 for (f_ix = 0; (unsigned int)f_ix !=
519 gi_ptr->n_functions;
520 f_ix++, tag = gcov_read_unsigned()) {
521 gfi_ptr = gi_ptr->functions[f_ix];
522
523 if (tag != GCOV_TAG_FUNCTION)
524 goto read_mismatch;
525
526 length = gcov_read_unsigned();
527 if (!length)
528 /* This function did not appear
529 * in the other program. We
530 * have nothing to merge.
531 */
532 continue;
533
534 if (length != GCOV_TAG_FUNCTION_LENGTH)
535 goto read_mismatch;
536
537 if (!gfi_ptr || gfi_ptr->key !=
538 gi_ptr) {
539 /* This function appears in the
540 * other program. We need to
541 * buffer the information in
542 * order to write it back out --
543 * we'll be inserting data
544 * before this point, so cannot
545 * simply keep the data in the
546 * file.
547 */
548 fn_tail = buffer_fn_data(
549 gi_filename, gi_ptr,
550 fn_tail, f_ix);
551 if (!fn_tail)
552 goto read_mismatch;
553 continue;
554 }
555
556 length = gcov_read_unsigned();
557 if (length != gfi_ptr->ident)
558 goto read_mismatch;
559
560 length = gcov_read_unsigned();
561 if (length != gfi_ptr->lineno_checksum)
562 goto read_mismatch;
563
564 length = gcov_read_unsigned();
565 if (length != gfi_ptr->cfg_checksum)
566 goto read_mismatch;
567
568 ci_ptr = gfi_ptr->ctrs;
569 for (t_ix = 0; t_ix < GCOV_COUNTERS;
570 t_ix++) {
571 gcov_merge_fn merge =
572 gi_ptr->merge[t_ix];
573
574 if (!merge)
575 continue;
576
577 tag = gcov_read_unsigned();
578 length = gcov_read_unsigned();
579 if (tag != GCOV_TAG_FOR_COUNTER(
580 t_ix) || length !=
581 GCOV_TAG_COUNTER_LENGTH(
582 ci_ptr->num))
583 goto read_mismatch;
584 (*merge)(ci_ptr->values,
585 ci_ptr->num);
586 ci_ptr++;
587 }
588 if ((error = gcov_is_error()))
589 goto read_error;
590 }
591
592 if (tag) {
593 read_mismatch:;
594 fprintf(stderr,
595 "profiling:%s:Merge mismatch for %s %u\n",
596 gi_filename, f_ix >= 0 ?
597 "function" : "summary",
598 f_ix < 0 ? -1 - f_ix : f_ix);
599 goto read_fatal;
600 }
601 }
602 goto rewrite;
603
604read_error:;
605 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
Lee Leahy35af5c42017-03-09 17:35:28 -0800606 error < 0 ? "Overflow" : "Error");
Lee Leahye20a3192017-03-09 16:21:34 -0800607
608 goto read_fatal;
609
610rewrite:;
611 gcov_rewrite();
612 if (!summary_pos) {
613 memset(&prg, 0, sizeof(prg));
614 summary_pos = eof_pos;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800615 }
616
Lee Leahye20a3192017-03-09 16:21:34 -0800617 /* Merge the summaries. */
618 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) {
619 cs_prg = &prg.ctrs[t_ix];
620 cs_tprg = &this_prg.ctrs[t_ix];
621 cs_all = &all_prg.ctrs[t_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800622
Lee Leahye20a3192017-03-09 16:21:34 -0800623 if (gi_ptr->merge[t_ix]) {
624 if (!cs_prg->runs++)
625 cs_prg->num = cs_tprg->num;
626 cs_prg->sum_all += cs_tprg->sum_all;
627 if (cs_prg->run_max < cs_tprg->run_max)
628 cs_prg->run_max = cs_tprg->run_max;
629 cs_prg->sum_max += cs_tprg->run_max;
630 } else if (cs_prg->runs)
631 goto read_mismatch;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800632
Lee Leahye20a3192017-03-09 16:21:34 -0800633 if (!cs_all->runs && cs_prg->runs)
634 memcpy(cs_all, cs_prg, sizeof(*cs_all));
635 else if (!all_prg.checksum
Lee Leahy73402172017-03-10 15:23:24 -0800636 && (!GCOV_LOCKED
637 || cs_all->runs == cs_prg->runs)
Lee Leahye20a3192017-03-09 16:21:34 -0800638 && memcmp(cs_all, cs_prg, sizeof(*cs_all))) {
639 fprintf(stderr,
640 "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
641 gi_filename, GCOV_LOCKED ? "" :
642 " or concurrently updated without locking support");
643 all_prg.checksum = ~0u;
644 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800645 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800646
Lee Leahye20a3192017-03-09 16:21:34 -0800647 prg.checksum = crc32;
648
649 /* Write out the data. */
650 if (!eof_pos) {
651 gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
652 gcov_write_unsigned(gi_ptr->stamp);
653 }
654
655 if (summary_pos)
656 gcov_seek(summary_pos);
657
658 /* Generate whole program statistics. */
659 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
660
661 if (summary_pos < eof_pos)
662 gcov_seek(eof_pos);
663
664 /* Write execution counts for each function. */
Lee Leahy73402172017-03-10 15:23:24 -0800665 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
666 f_ix++) {
Lee Leahye20a3192017-03-09 16:21:34 -0800667 unsigned int buffered = 0;
668
Lee Leahy73402172017-03-10 15:23:24 -0800669 if (fn_buffer && fn_buffer->fn_ix
670 == (unsigned int)f_ix) {
Lee Leahye20a3192017-03-09 16:21:34 -0800671 /* Buffered data from another program. */
672 buffered = 1;
673 gfi_ptr = &fn_buffer->info;
674 length = GCOV_TAG_FUNCTION_LENGTH;
675 } else {
676 gfi_ptr = gi_ptr->functions[f_ix];
677 if (gfi_ptr && gfi_ptr->key == gi_ptr)
678 length = GCOV_TAG_FUNCTION_LENGTH;
679 else
680 length = 0;
681 }
682
683 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
684 if (!length)
685 continue;
686
687 gcov_write_unsigned(gfi_ptr->ident);
688 gcov_write_unsigned(gfi_ptr->lineno_checksum);
689 gcov_write_unsigned(gfi_ptr->cfg_checksum);
690
691 ci_ptr = gfi_ptr->ctrs;
692 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) {
693 if (!gi_ptr->merge[t_ix])
694 continue;
695
696 n_counts = ci_ptr->num;
Lee Leahy73402172017-03-10 15:23:24 -0800697 gcov_write_tag_length(
698 GCOV_TAG_FOR_COUNTER(t_ix),
Lee Leahye20a3192017-03-09 16:21:34 -0800699 GCOV_TAG_COUNTER_LENGTH(n_counts));
700 gcov_type *c_ptr = ci_ptr->values;
701 while (n_counts--)
702 gcov_write_counter(*c_ptr++);
703 ci_ptr++;
704 }
705 if (buffered)
706 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
707 GCOV_COUNTERS);
708 }
709
710 gcov_write_unsigned(0);
711
712read_fatal:;
713 while (fn_buffer)
Lee Leahy73402172017-03-10 15:23:24 -0800714 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
715 GCOV_COUNTERS);
Lee Leahye20a3192017-03-09 16:21:34 -0800716
717 if ((error = gcov_close()))
718 fprintf(stderr, error < 0 ?
719 "profiling:%s:Overflow writing\n" :
720 "profiling:%s:Error writing\n",
721 gi_filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800722 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800723}
724
725/* Add a new object file onto the bb chain. Invoked automatically
726 when running an object file's global ctors. */
727
728void
Lee Leahy38768c32017-03-09 14:07:18 -0800729__gcov_init(struct gcov_info *info)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800730{
Lee Leahye20a3192017-03-09 16:21:34 -0800731 if (!info->version || !info->n_functions)
732 return;
733 if (gcov_version(info, info->version, 0)) {
734 size_t filename_length = strlen(info->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800735
Lee Leahye20a3192017-03-09 16:21:34 -0800736 /* Refresh the longest file name information */
737 if (filename_length > gcov_max_filename)
738 gcov_max_filename = filename_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800739
740#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800741 if (!gcov_list)
742 atexit(gcov_exit);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800743#endif
744
Lee Leahye20a3192017-03-09 16:21:34 -0800745 info->next = gcov_list;
746 gcov_list = info;
747 }
748 info->version = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800749}
750
751/* Called before fork or exec - write out profile information gathered so
752 far and reset it to zero. This avoids duplication or loss of the
753 profile information gathered so far. */
754
755void
Lee Leahy38768c32017-03-09 14:07:18 -0800756__gcov_flush(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800757{
Lee Leahye20a3192017-03-09 16:21:34 -0800758 const struct gcov_info *gi_ptr;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800759
Lee Leahye20a3192017-03-09 16:21:34 -0800760 gcov_exit();
761 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
762 unsigned int f_ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800763
Lee Leahye20a3192017-03-09 16:21:34 -0800764 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) {
765 unsigned int t_ix;
766 const struct gcov_fn_info *gfi_ptr =
767 gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800768
Lee Leahye20a3192017-03-09 16:21:34 -0800769 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
770 continue;
771 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
772 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) {
773 if (!gi_ptr->merge[t_ix])
774 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800775
Lee Leahye20a3192017-03-09 16:21:34 -0800776 memset(ci_ptr->values, 0,
777 sizeof(gcov_type) * ci_ptr->num);
778 ci_ptr++;
779 }
780 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800781 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800782}
783
784#endif /* L_gcov */
785
786#ifdef L_gcov_merge_add
787/* The profile merging function that just adds the counters. It is given
788 an array COUNTERS of N_COUNTERS old counters and it reads the same number
789 of counters from the gcov file. */
790void
Lee Leahy38768c32017-03-09 14:07:18 -0800791__gcov_merge_add(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800792{
Lee Leahye20a3192017-03-09 16:21:34 -0800793 for (; n_counters; counters++, n_counters--)
794 *counters += gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800795}
796#endif /* L_gcov_merge_add */
797
798#ifdef L_gcov_merge_ior
799/* The profile merging function that just adds the counters. It is given
800 an array COUNTERS of N_COUNTERS old counters and it reads the same number
801 of counters from the gcov file. */
802void
Lee Leahy38768c32017-03-09 14:07:18 -0800803__gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800804{
Lee Leahye20a3192017-03-09 16:21:34 -0800805 for (; n_counters; counters++, n_counters--)
806 *counters |= gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800807}
808#endif
809
810#ifdef L_gcov_merge_single
811/* The profile merging function for choosing the most common value.
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600812 * It is given an array COUNTERS of N_COUNTERS old counters and it
813 * reads the same number of counters from the gcov file. The counters
814 * are split into 3-tuples where the members of the tuple have
815 * meanings:
816 *
817 * -- the stored candidate on the most common value of the measured entity
818 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800819 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600820 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800821void
Lee Leahy38768c32017-03-09 14:07:18 -0800822__gcov_merge_single(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800823{
Lee Leahye20a3192017-03-09 16:21:34 -0800824 unsigned int i, n_measures;
825 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800826
Lee Leahye20a3192017-03-09 16:21:34 -0800827 gcc_assert(!(n_counters % 3));
828 n_measures = n_counters / 3;
829 for (i = 0; i < n_measures; i++, counters += 3) {
830 value = gcov_read_counter();
831 counter = gcov_read_counter();
832 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800833
Lee Leahye20a3192017-03-09 16:21:34 -0800834 if (counters[0] == value)
835 counters[1] += counter;
836 else if (counter > counters[1]) {
837 counters[0] = value;
838 counters[1] = counter - counters[1];
839 } else
840 counters[1] -= counter;
841 counters[2] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800842 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800843}
844#endif /* L_gcov_merge_single */
845
846#ifdef L_gcov_merge_delta
847/* The profile merging function for choosing the most common
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600848 * difference between two consecutive evaluations of the value. It is
849 * given an array COUNTERS of N_COUNTERS old counters and it reads the
850 * same number of counters from the gcov file. The counters are split
851 * into 4-tuples where the members of the tuple have meanings:
852 *
853 * -- the last value of the measured entity
854 * -- the stored candidate on the most common difference
855 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800856 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600857 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800858void
Lee Leahy38768c32017-03-09 14:07:18 -0800859__gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800860{
Lee Leahye20a3192017-03-09 16:21:34 -0800861 unsigned int i, n_measures;
862 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800863
Lee Leahye20a3192017-03-09 16:21:34 -0800864 gcc_assert(!(n_counters % 4));
865 n_measures = n_counters / 4;
866 for (i = 0; i < n_measures; i++, counters += 4) {
867 /* last = */
868 gcov_read_counter();
869 value = gcov_read_counter();
870 counter = gcov_read_counter();
871 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800872
Lee Leahye20a3192017-03-09 16:21:34 -0800873 if (counters[1] == value)
874 counters[2] += counter;
875 else if (counter > counters[2]) {
876 counters[1] = value;
877 counters[2] = counter - counters[2];
878 } else
879 counters[2] -= counter;
880 counters[3] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800881 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800882}
883#endif /* L_gcov_merge_delta */
884
885#ifdef L_gcov_interval_profiler
886/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
887 corresponding counter in COUNTERS. If the VALUE is above or below
888 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
889 instead. */
890
891void
Lee Leahy38768c32017-03-09 14:07:18 -0800892__gcov_interval_profiler(gcov_type *counters, gcov_type value,
Lee Leahy75b85992017-03-08 16:34:12 -0800893 int start, unsigned int steps)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800894{
Lee Leahye20a3192017-03-09 16:21:34 -0800895 gcov_type delta = value - start;
896 if (delta < 0)
897 counters[steps + 1]++;
898 else if (delta >= steps)
899 counters[steps]++;
900 else
901 counters[delta]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800902}
903#endif
904
905#ifdef L_gcov_pow2_profiler
906/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
907 COUNTERS[0] is incremented. */
908
909void
Lee Leahy38768c32017-03-09 14:07:18 -0800910__gcov_pow2_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800911{
Lee Leahye20a3192017-03-09 16:21:34 -0800912 if (value & (value - 1))
913 counters[0]++;
914 else
915 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800916}
917#endif
918
919/* Tries to determine the most common value among its inputs. Checks if the
920 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
921 is incremented. If this is not the case and COUNTERS[1] is not zero,
922 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
923 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
924 function is called more than 50% of the time with one value, this value
925 will be in COUNTERS[0] in the end.
926
927 In any case, COUNTERS[2] is incremented. */
928
929static inline void
Lee Leahy38768c32017-03-09 14:07:18 -0800930__gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800931{
Lee Leahye20a3192017-03-09 16:21:34 -0800932 if (value == counters[0])
933 counters[1]++;
934 else if (counters[1] == 0) {
935 counters[1] = 1;
936 counters[0] = value;
937 } else
938 counters[1]--;
939 counters[2]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800940}
941
942#ifdef L_gcov_one_value_profiler
943void
Lee Leahy38768c32017-03-09 14:07:18 -0800944__gcov_one_value_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800945{
Lee Leahye20a3192017-03-09 16:21:34 -0800946 __gcov_one_value_profiler_body(counters, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800947}
948#endif
949
950#ifdef L_gcov_indirect_call_profiler
951
952/* By default, the C++ compiler will use function addresses in the
953 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
954 tells the compiler to use function descriptors instead. The value
955 of this macro says how many words wide the descriptor is (normally 2),
956 but it may be dependent on target flags. Since we do not have access
957 to the target flags here we just check to see if it is set and use
958 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
959
960 It is assumed that the address of a function descriptor may be treated
961 as a pointer to a function. */
962
963#ifdef TARGET_VTABLE_USES_DESCRIPTORS
964#define VTABLE_USES_DESCRIPTORS 1
965#else
966#define VTABLE_USES_DESCRIPTORS 0
967#endif
968
969/* Tries to determine the most common value among its inputs. */
970void
Lee Leahy38768c32017-03-09 14:07:18 -0800971__gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
Lee Leahyb2d834a2017-03-08 16:52:22 -0800972 void *cur_func, void *callee_func)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800973{
Lee Leahye20a3192017-03-09 16:21:34 -0800974 /* If the C++ virtual tables contain function descriptors then one
975 * function may have multiple descriptors and we need to dereference
976 * the descriptors to see if they point to the same function.
977 */
978 if (cur_func == callee_func
979 || (VTABLE_USES_DESCRIPTORS && callee_func
980 && *(void **) cur_func == *(void **) callee_func))
981 __gcov_one_value_profiler_body(counter, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800982}
983#endif
984
985
986#ifdef L_gcov_average_profiler
987/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
988 to saturate up. */
989
990void
Lee Leahy38768c32017-03-09 14:07:18 -0800991__gcov_average_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800992{
Lee Leahye20a3192017-03-09 16:21:34 -0800993 counters[0] += value;
Lee Leahy35af5c42017-03-09 17:35:28 -0800994 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800995}
996#endif
997
998#ifdef L_gcov_ior_profiler
999/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1000 to saturate up. */
1001
1002void
Lee Leahy38768c32017-03-09 14:07:18 -08001003__gcov_ior_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001004{
Lee Leahye20a3192017-03-09 16:21:34 -08001005 *counters |= value;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001006}
1007#endif
1008
1009#ifdef L_gcov_fork
1010/* A wrapper for the fork function. Flushes the accumulated profiling data, so
1011 that they are not counted twice. */
1012
1013pid_t
Lee Leahy38768c32017-03-09 14:07:18 -08001014__gcov_fork(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001015{
Lee Leahye20a3192017-03-09 16:21:34 -08001016 __gcov_flush();
1017 return fork();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001018}
1019#endif
1020
1021#ifdef L_gcov_execl
1022/* A wrapper for the execl function. Flushes the accumulated profiling data, so
1023 that they are not lost. */
1024
1025int
Lee Leahy38768c32017-03-09 14:07:18 -08001026__gcov_execl(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001027{
Lee Leahye20a3192017-03-09 16:21:34 -08001028 va_list ap, aq;
1029 unsigned int i, length;
1030 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001031
Lee Leahye20a3192017-03-09 16:21:34 -08001032 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001033
Lee Leahye20a3192017-03-09 16:21:34 -08001034 va_start(ap, arg);
1035 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001036
Lee Leahye20a3192017-03-09 16:21:34 -08001037 length = 2;
1038 while (va_arg(ap, char *))
1039 length++;
1040 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001041
Lee Leahye20a3192017-03-09 16:21:34 -08001042 args = (char **) alloca(length * sizeof(void *));
1043 args[0] = arg;
1044 for (i = 1; i < length; i++)
1045 args[i] = va_arg(aq, char *);
1046 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001047
Lee Leahye20a3192017-03-09 16:21:34 -08001048 return execv(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001049}
1050#endif
1051
1052#ifdef L_gcov_execlp
Lee Leahy73402172017-03-10 15:23:24 -08001053/* A wrapper for the execlp function. Flushes the accumulated profiling data,
1054 * so that they are not lost.
1055 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001056
1057int
Lee Leahy38768c32017-03-09 14:07:18 -08001058__gcov_execlp(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001059{
Lee Leahye20a3192017-03-09 16:21:34 -08001060 va_list ap, aq;
1061 unsigned int i, length;
1062 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001063
Lee Leahye20a3192017-03-09 16:21:34 -08001064 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001065
Lee Leahye20a3192017-03-09 16:21:34 -08001066 va_start(ap, arg);
1067 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001068
Lee Leahye20a3192017-03-09 16:21:34 -08001069 length = 2;
1070 while (va_arg(ap, char *))
1071 length++;
1072 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001073
Lee Leahye20a3192017-03-09 16:21:34 -08001074 args = (char **) alloca(length * sizeof(void *));
1075 args[0] = arg;
1076 for (i = 1; i < length; i++)
1077 args[i] = va_arg(aq, char *);
1078 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001079
Lee Leahye20a3192017-03-09 16:21:34 -08001080 return execvp(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001081}
1082#endif
1083
1084#ifdef L_gcov_execle
Lee Leahy73402172017-03-10 15:23:24 -08001085/* A wrapper for the execle function. Flushes the accumulated profiling data,
1086 * so that they are not lost.
1087 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001088
1089int
Lee Leahy38768c32017-03-09 14:07:18 -08001090__gcov_execle(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001091{
Lee Leahye20a3192017-03-09 16:21:34 -08001092 va_list ap, aq;
1093 unsigned int i, length;
1094 char **args;
1095 char **envp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001096
Lee Leahye20a3192017-03-09 16:21:34 -08001097 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001098
Lee Leahye20a3192017-03-09 16:21:34 -08001099 va_start(ap, arg);
1100 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001101
Lee Leahye20a3192017-03-09 16:21:34 -08001102 length = 2;
1103 while (va_arg(ap, char *))
1104 length++;
1105 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001106
Lee Leahye20a3192017-03-09 16:21:34 -08001107 args = (char **) alloca(length * sizeof(void *));
1108 args[0] = arg;
1109 for (i = 1; i < length; i++)
1110 args[i] = va_arg(aq, char *);
1111 envp = va_arg(aq, char **);
1112 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001113
Lee Leahye20a3192017-03-09 16:21:34 -08001114 return execve(path, args, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001115}
1116#endif
1117
1118#ifdef L_gcov_execv
1119/* A wrapper for the execv function. Flushes the accumulated profiling data, so
1120 that they are not lost. */
1121
1122int
Lee Leahy38768c32017-03-09 14:07:18 -08001123__gcov_execv(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001124{
Lee Leahye20a3192017-03-09 16:21:34 -08001125 __gcov_flush();
1126 return execv(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001127}
1128#endif
1129
1130#ifdef L_gcov_execvp
Lee Leahy73402172017-03-10 15:23:24 -08001131/* A wrapper for the execvp function. Flushes the accumulated profiling data,
1132 * so that they are not lost.
1133 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001134
1135int
Lee Leahy38768c32017-03-09 14:07:18 -08001136__gcov_execvp(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001137{
Lee Leahye20a3192017-03-09 16:21:34 -08001138 __gcov_flush();
1139 return execvp(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001140}
1141#endif
1142
1143#ifdef L_gcov_execve
Lee Leahy73402172017-03-10 15:23:24 -08001144/* A wrapper for the execve function. Flushes the accumulated profiling data,
1145 * so that they are not lost.
1146 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001147
1148int
Lee Leahy38768c32017-03-09 14:07:18 -08001149__gcov_execve(const char *path, char *const argv[], char *const envp[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001150{
Lee Leahye20a3192017-03-09 16:21:34 -08001151 __gcov_flush();
1152 return execve(path, argv, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001153}
1154#endif
1155#endif /* inhibit_libc */