blob: 61304ff4e320331acb85cf968cbbe76907efdaee [file] [log] [blame]
Martin Rothfb8876d2022-08-07 15:12:12 -06001/* SPDX-License-Identifier: GPL-3.0-only WITH GCC-exception-3.1 */
2
Stefan Reinauerd37ab452012-12-18 16:23:28 -08003/* 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.
8
9This file is part of GCC.
10
11GCC is free software; you can redistribute it and/or modify it under
12the terms of the GNU General Public License as published by the Free
13Software Foundation; either version 3, or (at your option) any later
14version.
15
16GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17WARRANTY; without even the implied warranty of MERCHANTABILITY or
18FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19for more details.
20
21Under Section 7 of GPL version 3, you are granted additional
22permissions described in the GCC Runtime Library Exception, version
233.1, as published by the Free Software Foundation.
Patrick Georgia73b9312015-10-31 11:55:10 +010024*/
Stefan Reinauerd37ab452012-12-18 16:23:28 -080025
Stefan Reinauerd37ab452012-12-18 16:23:28 -080026#ifdef __COREBOOT__
27#include <stdlib.h>
28#include <string.h>
Angel Pons9a5dd7a2020-07-27 20:28:27 +020029#include <commonlib/helpers.h>
Stefan Reinauerd37ab452012-12-18 16:23:28 -080030#include <console/console.h>
31#include <assert.h>
32typedef s32 pid_t;
33#define gcc_assert(x) ASSERT(x)
34#define fprintf(file, x...) printk(BIOS_ERR, x)
Stefan Reinauerd37ab452012-12-18 16:23:28 -080035#include "gcov-glue.c"
36
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
45
46# define HAVE_CC_TLS 0
47# define __GCOV_KERNEL__
48
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__ */
58
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"
72
73#if defined(inhibit_libc)
74/* If libc and its header files are not available, provide dummy functions. */
75
76#ifdef L_gcov
Stefan Reinauer6a001132017-07-13 02:20:27 +020077void __gcov_init(struct gcov_info *p __attribute__((unused))) {}
Lee Leahy38768c32017-03-09 14:07:18 -080078void __gcov_flush(void) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080079#endif
80
81#ifdef L_gcov_merge_add
Stefan Reinauer6a001132017-07-13 02:20:27 +020082void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
83 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080084#endif
85
86#ifdef L_gcov_merge_single
Stefan Reinauer6a001132017-07-13 02:20:27 +020087void __gcov_merge_single(gcov_type *counters __attribute__((unused)),
88 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080089#endif
90
91#ifdef L_gcov_merge_delta
Stefan Reinauer6a001132017-07-13 02:20:27 +020092void __gcov_merge_delta(gcov_type *counters __attribute__((unused)),
93 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080094#endif
95
96#else
97
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
Stefan Reinauer6a001132017-07-13 02:20:27 +0200106void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
107 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800108#endif /* __COREBOOT__ */
109
110#ifdef L_gcov
111#include "gcov-io.c"
112
Lee Leahy342f8d62017-03-10 15:31:56 -0800113struct gcov_fn_buffer {
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;
Elyes HAOUAS1d3fde42018-06-05 08:41:29 +0200413 struct gcov_fn_buffer *fn_buffer = NULL;
Lee Leahye20a3192017-03-09 16:21:34 -0800414 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);
Lee Leahy491c5b62017-03-10 15:51:04 -0800500 error = gcov_is_error();
501 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800502 goto read_error;
503 if (summary_pos
504 || tmp.checksum != crc32)
505 goto next_summary;
506
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;
514
515 next_summary:;
516 }
517
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];
523
524 if (tag != GCOV_TAG_FUNCTION)
525 goto read_mismatch;
526
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.
532 */
533 continue;
534
535 if (length != GCOV_TAG_FUNCTION_LENGTH)
536 goto read_mismatch;
537
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.
548 */
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;
555 }
556
557 length = gcov_read_unsigned();
558 if (length != gfi_ptr->ident)
559 goto read_mismatch;
560
561 length = gcov_read_unsigned();
562 if (length != gfi_ptr->lineno_checksum)
563 goto read_mismatch;
564
565 length = gcov_read_unsigned();
566 if (length != gfi_ptr->cfg_checksum)
567 goto read_mismatch;
568
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];
574
575 if (!merge)
576 continue;
577
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++;
588 }
Lee Leahy491c5b62017-03-10 15:51:04 -0800589 error = gcov_is_error();
590 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800591 goto read_error;
592 }
593
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;
602 }
603 }
604 goto rewrite;
605
606read_error:;
607 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
Lee Leahy35af5c42017-03-09 17:35:28 -0800608 error < 0 ? "Overflow" : "Error");
Lee Leahye20a3192017-03-09 16:21:34 -0800609
610 goto read_fatal;
611
612rewrite:;
613 gcov_rewrite();
614 if (!summary_pos) {
615 memset(&prg, 0, sizeof(prg));
616 summary_pos = eof_pos;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800617 }
618
Lee Leahye20a3192017-03-09 16:21:34 -0800619 /* 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];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800624
Lee Leahye20a3192017-03-09 16:21:34 -0800625 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800634
Lee Leahye20a3192017-03-09 16:21:34 -0800635 if (!cs_all->runs && cs_prg->runs)
636 memcpy(cs_all, cs_prg, sizeof(*cs_all));
637 else if (!all_prg.checksum
Lee Leahy73402172017-03-10 15:23:24 -0800638 && (!GCOV_LOCKED
639 || cs_all->runs == cs_prg->runs)
Lee Leahye20a3192017-03-09 16:21:34 -0800640 && 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;
646 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800647 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800648
Lee Leahye20a3192017-03-09 16:21:34 -0800649 prg.checksum = crc32;
650
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);
655 }
656
657 if (summary_pos)
658 gcov_seek(summary_pos);
659
660 /* Generate whole program statistics. */
661 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
662
663 if (summary_pos < eof_pos)
664 gcov_seek(eof_pos);
665
666 /* Write execution counts for each function. */
Lee Leahy73402172017-03-10 15:23:24 -0800667 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
668 f_ix++) {
Lee Leahye20a3192017-03-09 16:21:34 -0800669 unsigned int buffered = 0;
670
Lee Leahy73402172017-03-10 15:23:24 -0800671 if (fn_buffer && fn_buffer->fn_ix
672 == (unsigned int)f_ix) {
Lee Leahye20a3192017-03-09 16:21:34 -0800673 /* 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;
683 }
684
685 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
686 if (!length)
687 continue;
688
689 gcov_write_unsigned(gfi_ptr->ident);
690 gcov_write_unsigned(gfi_ptr->lineno_checksum);
691 gcov_write_unsigned(gfi_ptr->cfg_checksum);
692
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;
697
698 n_counts = ci_ptr->num;
Lee Leahy73402172017-03-10 15:23:24 -0800699 gcov_write_tag_length(
700 GCOV_TAG_FOR_COUNTER(t_ix),
Lee Leahye20a3192017-03-09 16:21:34 -0800701 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++;
706 }
707 if (buffered)
708 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
709 GCOV_COUNTERS);
710 }
711
712 gcov_write_unsigned(0);
713
714read_fatal:;
715 while (fn_buffer)
Lee Leahy73402172017-03-10 15:23:24 -0800716 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
717 GCOV_COUNTERS);
Lee Leahye20a3192017-03-09 16:21:34 -0800718
Lee Leahy491c5b62017-03-10 15:51:04 -0800719 error = gcov_close();
720 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800721 fprintf(stderr, error < 0 ?
722 "profiling:%s:Overflow writing\n" :
723 "profiling:%s:Error writing\n",
724 gi_filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800725 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800726}
727
728/* Add a new object file onto the bb chain. Invoked automatically
729 when running an object file's global ctors. */
730
731void
Lee Leahy38768c32017-03-09 14:07:18 -0800732__gcov_init(struct gcov_info *info)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800733{
Lee Leahye20a3192017-03-09 16:21:34 -0800734 if (!info->version || !info->n_functions)
735 return;
736 if (gcov_version(info, info->version, 0)) {
737 size_t filename_length = strlen(info->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800738
Lee Leahye20a3192017-03-09 16:21:34 -0800739 /* Refresh the longest file name information */
740 if (filename_length > gcov_max_filename)
741 gcov_max_filename = filename_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800742
743#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800744 if (!gcov_list)
745 atexit(gcov_exit);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800746#endif
747
Lee Leahye20a3192017-03-09 16:21:34 -0800748 info->next = gcov_list;
749 gcov_list = info;
750 }
751 info->version = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800752}
753
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. */
757
758void
Lee Leahy38768c32017-03-09 14:07:18 -0800759__gcov_flush(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800760{
Lee Leahye20a3192017-03-09 16:21:34 -0800761 const struct gcov_info *gi_ptr;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800762
Lee Leahye20a3192017-03-09 16:21:34 -0800763 gcov_exit();
764 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
765 unsigned int f_ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800766
Lee Leahye20a3192017-03-09 16:21:34 -0800767 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];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800771
Lee Leahye20a3192017-03-09 16:21:34 -0800772 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800778
Lee Leahye20a3192017-03-09 16:21:34 -0800779 memset(ci_ptr->values, 0,
780 sizeof(gcov_type) * ci_ptr->num);
781 ci_ptr++;
782 }
783 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800784 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800785}
786
787#endif /* L_gcov */
788
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. */
793void
Lee Leahy38768c32017-03-09 14:07:18 -0800794__gcov_merge_add(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800795{
Lee Leahye20a3192017-03-09 16:21:34 -0800796 for (; n_counters; counters++, n_counters--)
797 *counters += gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800798}
799#endif /* L_gcov_merge_add */
800
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. */
805void
Lee Leahy38768c32017-03-09 14:07:18 -0800806__gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800807{
Lee Leahye20a3192017-03-09 16:21:34 -0800808 for (; n_counters; counters++, n_counters--)
809 *counters |= gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800810}
811#endif
812
813#ifdef L_gcov_merge_single
814/* The profile merging function for choosing the most common value.
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600815 * 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:
819 *
820 * -- the stored candidate on the most common value of the measured entity
821 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800822 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600823 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800824void
Lee Leahy38768c32017-03-09 14:07:18 -0800825__gcov_merge_single(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800826{
Lee Leahye20a3192017-03-09 16:21:34 -0800827 unsigned int i, n_measures;
828 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800829
Lee Leahye20a3192017-03-09 16:21:34 -0800830 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();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800836
Lee Leahye20a3192017-03-09 16:21:34 -0800837 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800845 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800846}
847#endif /* L_gcov_merge_single */
848
849#ifdef L_gcov_merge_delta
850/* The profile merging function for choosing the most common
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600851 * 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:
855 *
856 * -- the last value of the measured entity
857 * -- the stored candidate on the most common difference
858 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800859 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600860 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800861void
Lee Leahy38768c32017-03-09 14:07:18 -0800862__gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800863{
Lee Leahye20a3192017-03-09 16:21:34 -0800864 unsigned int i, n_measures;
865 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800866
Lee Leahye20a3192017-03-09 16:21:34 -0800867 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();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800875
Lee Leahye20a3192017-03-09 16:21:34 -0800876 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;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800884 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800885}
886#endif /* L_gcov_merge_delta */
887
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. */
893
894void
Lee Leahy38768c32017-03-09 14:07:18 -0800895__gcov_interval_profiler(gcov_type *counters, gcov_type value,
Lee Leahy75b85992017-03-08 16:34:12 -0800896 int start, unsigned int steps)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800897{
Lee Leahye20a3192017-03-09 16:21:34 -0800898 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]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800905}
906#endif
907
908#ifdef L_gcov_pow2_profiler
909/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
910 COUNTERS[0] is incremented. */
911
912void
Lee Leahy38768c32017-03-09 14:07:18 -0800913__gcov_pow2_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800914{
Lee Leahye20a3192017-03-09 16:21:34 -0800915 if (value & (value - 1))
916 counters[0]++;
917 else
918 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800919}
920#endif
921
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.
929
930 In any case, COUNTERS[2] is incremented. */
931
932static inline void
Lee Leahy38768c32017-03-09 14:07:18 -0800933__gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800934{
Lee Leahye20a3192017-03-09 16:21:34 -0800935 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]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800943}
944
945#ifdef L_gcov_one_value_profiler
946void
Lee Leahy38768c32017-03-09 14:07:18 -0800947__gcov_one_value_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800948{
Lee Leahye20a3192017-03-09 16:21:34 -0800949 __gcov_one_value_profiler_body(counters, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800950}
951#endif
952
953#ifdef L_gcov_indirect_call_profiler
954
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.
962
963 It is assumed that the address of a function descriptor may be treated
964 as a pointer to a function. */
965
966#ifdef TARGET_VTABLE_USES_DESCRIPTORS
967#define VTABLE_USES_DESCRIPTORS 1
968#else
969#define VTABLE_USES_DESCRIPTORS 0
970#endif
971
972/* Tries to determine the most common value among its inputs. */
973void
Lee Leahy38768c32017-03-09 14:07:18 -0800974__gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
Lee Leahyb2d834a2017-03-08 16:52:22 -0800975 void *cur_func, void *callee_func)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800976{
Lee Leahye20a3192017-03-09 16:21:34 -0800977 /* 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.
980 */
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);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800985}
986#endif
987
988
989#ifdef L_gcov_average_profiler
990/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
991 to saturate up. */
992
993void
Lee Leahy38768c32017-03-09 14:07:18 -0800994__gcov_average_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800995{
Lee Leahye20a3192017-03-09 16:21:34 -0800996 counters[0] += value;
Lee Leahy35af5c42017-03-09 17:35:28 -0800997 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800998}
999#endif
1000
1001#ifdef L_gcov_ior_profiler
1002/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1003 to saturate up. */
1004
1005void
Lee Leahy38768c32017-03-09 14:07:18 -08001006__gcov_ior_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001007{
Lee Leahye20a3192017-03-09 16:21:34 -08001008 *counters |= value;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001009}
1010#endif
1011
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. */
1015
1016pid_t
Lee Leahy38768c32017-03-09 14:07:18 -08001017__gcov_fork(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001018{
Lee Leahye20a3192017-03-09 16:21:34 -08001019 __gcov_flush();
1020 return fork();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001021}
1022#endif
1023
1024#ifdef L_gcov_execl
1025/* A wrapper for the execl function. Flushes the accumulated profiling data, so
1026 that they are not lost. */
1027
1028int
Lee Leahy38768c32017-03-09 14:07:18 -08001029__gcov_execl(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001030{
Lee Leahye20a3192017-03-09 16:21:34 -08001031 va_list ap, aq;
1032 unsigned int i, length;
1033 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001034
Lee Leahye20a3192017-03-09 16:21:34 -08001035 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001036
Lee Leahye20a3192017-03-09 16:21:34 -08001037 va_start(ap, arg);
1038 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001039
Lee Leahye20a3192017-03-09 16:21:34 -08001040 length = 2;
1041 while (va_arg(ap, char *))
1042 length++;
1043 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001044
Lee Leahye20a3192017-03-09 16:21:34 -08001045 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);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001050
Lee Leahye20a3192017-03-09 16:21:34 -08001051 return execv(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001052}
1053#endif
1054
1055#ifdef L_gcov_execlp
Lee Leahy73402172017-03-10 15:23:24 -08001056/* A wrapper for the execlp function. Flushes the accumulated profiling data,
1057 * so that they are not lost.
1058 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001059
1060int
Lee Leahy38768c32017-03-09 14:07:18 -08001061__gcov_execlp(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001062{
Lee Leahye20a3192017-03-09 16:21:34 -08001063 va_list ap, aq;
1064 unsigned int i, length;
1065 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001066
Lee Leahye20a3192017-03-09 16:21:34 -08001067 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001068
Lee Leahye20a3192017-03-09 16:21:34 -08001069 va_start(ap, arg);
1070 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001071
Lee Leahye20a3192017-03-09 16:21:34 -08001072 length = 2;
1073 while (va_arg(ap, char *))
1074 length++;
1075 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001076
Lee Leahye20a3192017-03-09 16:21:34 -08001077 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);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001082
Lee Leahye20a3192017-03-09 16:21:34 -08001083 return execvp(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001084}
1085#endif
1086
1087#ifdef L_gcov_execle
Lee Leahy73402172017-03-10 15:23:24 -08001088/* A wrapper for the execle function. Flushes the accumulated profiling data,
1089 * so that they are not lost.
1090 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001091
1092int
Lee Leahy38768c32017-03-09 14:07:18 -08001093__gcov_execle(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001094{
Lee Leahye20a3192017-03-09 16:21:34 -08001095 va_list ap, aq;
1096 unsigned int i, length;
1097 char **args;
1098 char **envp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001099
Lee Leahye20a3192017-03-09 16:21:34 -08001100 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001101
Lee Leahye20a3192017-03-09 16:21:34 -08001102 va_start(ap, arg);
1103 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001104
Lee Leahye20a3192017-03-09 16:21:34 -08001105 length = 2;
1106 while (va_arg(ap, char *))
1107 length++;
1108 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001109
Lee Leahye20a3192017-03-09 16:21:34 -08001110 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);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001116
Lee Leahye20a3192017-03-09 16:21:34 -08001117 return execve(path, args, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001118}
1119#endif
1120
1121#ifdef L_gcov_execv
1122/* A wrapper for the execv function. Flushes the accumulated profiling data, so
1123 that they are not lost. */
1124
1125int
Lee Leahy38768c32017-03-09 14:07:18 -08001126__gcov_execv(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001127{
Lee Leahye20a3192017-03-09 16:21:34 -08001128 __gcov_flush();
1129 return execv(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001130}
1131#endif
1132
1133#ifdef L_gcov_execvp
Lee Leahy73402172017-03-10 15:23:24 -08001134/* A wrapper for the execvp function. Flushes the accumulated profiling data,
1135 * so that they are not lost.
1136 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001137
1138int
Lee Leahy38768c32017-03-09 14:07:18 -08001139__gcov_execvp(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001140{
Lee Leahye20a3192017-03-09 16:21:34 -08001141 __gcov_flush();
1142 return execvp(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001143}
1144#endif
1145
1146#ifdef L_gcov_execve
Lee Leahy73402172017-03-10 15:23:24 -08001147/* A wrapper for the execve function. Flushes the accumulated profiling data,
1148 * so that they are not lost.
1149 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001150
1151int
Lee Leahy38768c32017-03-09 14:07:18 -08001152__gcov_execve(const char *path, char *const argv[], char *const envp[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001153{
Lee Leahye20a3192017-03-09 16:21:34 -08001154 __gcov_flush();
1155 return execve(path, argv, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001156}
1157#endif
1158#endif /* inhibit_libc */