blob: b0c816181d1ee357dfd291a1e2612c46ee499fdf [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
26#define __COREBOOT__
27#ifdef __COREBOOT__
28#include <stdlib.h>
29#include <string.h>
Angel Pons9a5dd7a2020-07-27 20:28:27 +020030#include <commonlib/helpers.h>
Stefan Reinauerd37ab452012-12-18 16:23:28 -080031#include <console/console.h>
32#include <assert.h>
33typedef s32 pid_t;
34#define gcc_assert(x) ASSERT(x)
35#define fprintf(file, x...) printk(BIOS_ERR, x)
Stefan Reinauerd37ab452012-12-18 16:23:28 -080036#include "gcov-glue.c"
37
38/* Define MACROs to be used by coreboot compilation. */
39# define L_gcov
40# define L_gcov_interval_profiler
41# define L_gcov_pow2_profiler
42# define L_gcov_one_value_profiler
43# define L_gcov_indirect_call_profiler
44# define L_gcov_average_profiler
45# define L_gcov_ior_profiler
46
47# define HAVE_CC_TLS 0
48# define __GCOV_KERNEL__
49
50# define IN_LIBGCOV 1
51# define IN_GCOV 0
52#else /* __COREBOOT__ */
53#include "tconfig.h"
54#include "tsystem.h"
55#include "coretypes.h"
56#include "tm.h"
57#include "libgcc_tm.h"
58#endif /* __COREBOOT__ */
59
60#ifndef __COREBOOT__
61#if defined(inhibit_libc)
62#define IN_LIBGCOV (-1)
63#else
64#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
65#include <stdio.h>
66#define IN_LIBGCOV 1
67#if defined(L_gcov)
68#define GCOV_LINKAGE /* nothing */
69#endif
70#endif
71#endif /* __COREBOOT__ */
72#include "gcov-io.h"
73
74#if defined(inhibit_libc)
75/* If libc and its header files are not available, provide dummy functions. */
76
77#ifdef L_gcov
Stefan Reinauer6a001132017-07-13 02:20:27 +020078void __gcov_init(struct gcov_info *p __attribute__((unused))) {}
Lee Leahy38768c32017-03-09 14:07:18 -080079void __gcov_flush(void) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080080#endif
81
82#ifdef L_gcov_merge_add
Stefan Reinauer6a001132017-07-13 02:20:27 +020083void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
84 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080085#endif
86
87#ifdef L_gcov_merge_single
Stefan Reinauer6a001132017-07-13 02:20:27 +020088void __gcov_merge_single(gcov_type *counters __attribute__((unused)),
89 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080090#endif
91
92#ifdef L_gcov_merge_delta
Stefan Reinauer6a001132017-07-13 02:20:27 +020093void __gcov_merge_delta(gcov_type *counters __attribute__((unused)),
94 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080095#endif
96
97#else
98
99#ifndef __COREBOOT__
100#include <string.h>
101#if GCOV_LOCKED
102#include <fcntl.h>
103#include <errno.h>
104#include <sys/stat.h>
105#endif
106#else
Stefan Reinauer6a001132017-07-13 02:20:27 +0200107void __gcov_merge_add(gcov_type *counters __attribute__((unused)),
108 unsigned int n_counters __attribute__((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800109#endif /* __COREBOOT__ */
110
111#ifdef L_gcov
112#include "gcov-io.c"
113
Lee Leahy342f8d62017-03-10 15:31:56 -0800114struct gcov_fn_buffer {
Lee Leahye20a3192017-03-09 16:21:34 -0800115 struct gcov_fn_buffer *next;
116 unsigned int fn_ix;
117 struct gcov_fn_info info;
118 /* note gcov_fn_info ends in a trailing array. */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800119};
120
121/* Chain of per-object gcov structures. */
122static struct gcov_info *gcov_list;
123
124/* Size of the longest file name. */
125static size_t gcov_max_filename = 0;
126
127/* Make sure path component of the given FILENAME exists, create
128 missing directories. FILENAME must be writable.
129 Returns zero on success, or -1 if an error occurred. */
130
131static int
Lee Leahy38768c32017-03-09 14:07:18 -0800132create_file_directory(char *filename)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800133{
134#ifdef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800135 (void) filename;
136 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800137#else
138#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
Lee Leahye20a3192017-03-09 16:21:34 -0800139 (void) filename;
140 return -1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800141#else
Lee Leahye20a3192017-03-09 16:21:34 -0800142 char *s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800143
Lee Leahye20a3192017-03-09 16:21:34 -0800144 s = filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800145
Lee Leahye20a3192017-03-09 16:21:34 -0800146 if (HAS_DRIVE_SPEC(s))
147 s += 2;
148 if (IS_DIR_SEPARATOR(*s))
149 ++s;
150 for (; *s != '\0'; s++)
151 if (IS_DIR_SEPARATOR(*s)) {
152 char sep = *s;
153 *s = '\0';
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800154
Lee Leahye20a3192017-03-09 16:21:34 -0800155 /* Try to make directory if it doesn't already exist. */
156 if (access(filename, F_OK) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800157#ifdef TARGET_POSIX_IO
Lee Leahye20a3192017-03-09 16:21:34 -0800158 && mkdir(filename, 0755) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800159#else
Lee Leahye20a3192017-03-09 16:21:34 -0800160 && mkdir(filename) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800161#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800162 /* The directory might have been made by another
163 * process.
164 */
165 && errno != EEXIST) {
166 fprintf(stderr,
167 "profiling:%s:Cannot create directory\n",
168 filename);
169 *s = sep;
170 return -1;
171 };
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800172
Lee Leahye20a3192017-03-09 16:21:34 -0800173 *s = sep;
174 };
175 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800176#endif
177#endif
178}
179
180static struct gcov_fn_buffer *
Lee Leahy38768c32017-03-09 14:07:18 -0800181free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
Lee Leahy75b85992017-03-08 16:34:12 -0800182 unsigned int limit)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800183{
Lee Leahye20a3192017-03-09 16:21:34 -0800184 struct gcov_fn_buffer *next;
185 unsigned int ix, n_ctr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800186
Lee Leahye20a3192017-03-09 16:21:34 -0800187 if (!buffer)
188 return 0;
189 next = buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800190
Lee Leahye20a3192017-03-09 16:21:34 -0800191 for (ix = 0; ix != limit; ix++)
192 if (gi_ptr->merge[ix])
193 free(buffer->info.ctrs[n_ctr++].values);
194 free(buffer);
195 return next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800196}
197
198static struct gcov_fn_buffer **
Lee Leahy38768c32017-03-09 14:07:18 -0800199buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr,
Lee Leahy75b85992017-03-08 16:34:12 -0800200 struct gcov_fn_buffer **end_ptr, unsigned int fn_ix)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800201{
Lee Leahye20a3192017-03-09 16:21:34 -0800202 unsigned int n_ctrs = 0, ix = 0;
203 struct gcov_fn_buffer *fn_buffer;
204 unsigned int len;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800205
Lee Leahye20a3192017-03-09 16:21:34 -0800206 for (ix = GCOV_COUNTERS; ix--;)
207 if (gi_ptr->merge[ix])
208 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800209
Lee Leahye20a3192017-03-09 16:21:34 -0800210 len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs;
211 fn_buffer = (struct gcov_fn_buffer *)malloc(len);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800212
Lee Leahye20a3192017-03-09 16:21:34 -0800213 if (!fn_buffer)
214 goto fail;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800215
Lee Leahye20a3192017-03-09 16:21:34 -0800216 fn_buffer->next = 0;
217 fn_buffer->fn_ix = fn_ix;
218 fn_buffer->info.ident = gcov_read_unsigned();
219 fn_buffer->info.lineno_checksum = gcov_read_unsigned();
220 fn_buffer->info.cfg_checksum = gcov_read_unsigned();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800221
Lee Leahye20a3192017-03-09 16:21:34 -0800222 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) {
223 gcov_unsigned_t length;
224 gcov_type *values;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800225
Lee Leahye20a3192017-03-09 16:21:34 -0800226 if (!gi_ptr->merge[ix])
227 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800228
Lee Leahye20a3192017-03-09 16:21:34 -0800229 if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) {
230 len = 0;
231 goto fail;
232 }
233
234 length = GCOV_TAG_COUNTER_NUM(gcov_read_unsigned());
235 len = length * sizeof(gcov_type);
236 values = (gcov_type *)malloc(len);
237 if (!values)
238 goto fail;
239
240 fn_buffer->info.ctrs[n_ctrs].num = length;
241 fn_buffer->info.ctrs[n_ctrs].values = values;
242
243 while (length--)
244 *values++ = gcov_read_counter();
245 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800246 }
247
Lee Leahye20a3192017-03-09 16:21:34 -0800248 *end_ptr = fn_buffer;
249 return &fn_buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800250
251fail:
Lee Leahy35af5c42017-03-09 17:35:28 -0800252 fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix,
Lee Leahye20a3192017-03-09 16:21:34 -0800253 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800254
Lee Leahye20a3192017-03-09 16:21:34 -0800255 return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800256}
257
258/* Add an unsigned value to the current crc */
259
260static gcov_unsigned_t
Lee Leahy38768c32017-03-09 14:07:18 -0800261crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800262{
Lee Leahye20a3192017-03-09 16:21:34 -0800263 unsigned int ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800264
Lee Leahye20a3192017-03-09 16:21:34 -0800265 for (ix = 32; ix--; value <<= 1) {
266 unsigned int feedback;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800267
Lee Leahye20a3192017-03-09 16:21:34 -0800268 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
269 crc32 <<= 1;
270 crc32 ^= feedback;
271 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800272
Lee Leahye20a3192017-03-09 16:21:34 -0800273 return crc32;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800274}
275
276/* Check if VERSION of the info block PTR matches libgcov one.
277 Return 1 on success, or zero in case of versions mismatch.
278 If FILENAME is not NULL, its value used for reporting purposes
279 instead of value from the info block. */
280
281static int
Lee Leahy38768c32017-03-09 14:07:18 -0800282gcov_version(struct gcov_info *ptr, gcov_unsigned_t version,
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800283 const char *filename)
284{
Lee Leahye20a3192017-03-09 16:21:34 -0800285 if (version != GCOV_VERSION) {
286 char v[4], e[4];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800287
Lee Leahye20a3192017-03-09 16:21:34 -0800288 GCOV_UNSIGNED2STRING(v, version);
289 GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800290
Lee Leahye20a3192017-03-09 16:21:34 -0800291 fprintf(stderr,
292 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
Lee Leahy35af5c42017-03-09 17:35:28 -0800293 filename ? filename : ptr->filename, e, v);
Lee Leahye20a3192017-03-09 16:21:34 -0800294 return 0;
295 }
296 return 1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800297}
298
299/* Dump the coverage counts. We merge with existing counts when
300 possible, to avoid growing the .da files ad infinitum. We use this
301 program's checksum to make sure we only accumulate whole program
302 statistics to the correct summary. An object file might be embedded
303 in two separate programs, and we must keep the two program
304 summaries separate. */
305
306static void
Lee Leahy38768c32017-03-09 14:07:18 -0800307gcov_exit(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800308{
Lee Leahye20a3192017-03-09 16:21:34 -0800309 struct gcov_info *gi_ptr;
310 const struct gcov_fn_info *gfi_ptr;
311 struct gcov_summary this_prg; /* summary for program. */
312 struct gcov_summary all_prg; /* summary for all instances of program. */
313 struct gcov_ctr_summary *cs_ptr;
314 const struct gcov_ctr_info *ci_ptr;
315 unsigned int t_ix;
316 int f_ix = 0;
317 gcov_unsigned_t c_num;
318 const char *gcov_prefix;
319 int gcov_prefix_strip = 0;
320 size_t prefix_length;
321 char *gi_filename, *gi_filename_up;
322 gcov_unsigned_t crc32 = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800323
Lee Leahye20a3192017-03-09 16:21:34 -0800324 memset(&all_prg, 0, sizeof(all_prg));
325 /* Find the totals for this execution. */
326 memset(&this_prg, 0, sizeof(this_prg));
327 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
328 crc32 = crc32_unsigned(crc32, gi_ptr->stamp);
329 crc32 = crc32_unsigned(crc32, gi_ptr->n_functions);
Kyösti Mälkkiecd84242013-09-13 07:57:49 +0300330
Lee Leahye20a3192017-03-09 16:21:34 -0800331 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
332 f_ix++) {
333 gfi_ptr = gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800334
Lee Leahye20a3192017-03-09 16:21:34 -0800335 if (gfi_ptr && gfi_ptr->key != gi_ptr)
336 gfi_ptr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800337
Lee Leahye20a3192017-03-09 16:21:34 -0800338 crc32 = crc32_unsigned(crc32, gfi_ptr
339 ? gfi_ptr->cfg_checksum : 0);
340 crc32 = crc32_unsigned(crc32,
341 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
342 if (!gfi_ptr)
343 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800344
Lee Leahye20a3192017-03-09 16:21:34 -0800345 ci_ptr = gfi_ptr->ctrs;
346 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) {
347 if (!gi_ptr->merge[t_ix])
348 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800349
Lee Leahye20a3192017-03-09 16:21:34 -0800350 cs_ptr = &this_prg.ctrs[t_ix];
351 cs_ptr->num += ci_ptr->num;
352 crc32 = crc32_unsigned(crc32, ci_ptr->num);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800353
Lee Leahye20a3192017-03-09 16:21:34 -0800354 for (c_num = 0; c_num < ci_ptr->num; c_num++) {
355 cs_ptr->sum_all +=
356 ci_ptr->values[c_num];
357 if (cs_ptr->run_max
358 < ci_ptr->values[c_num])
359 cs_ptr->run_max =
360 ci_ptr->values[c_num];
361 }
362 ci_ptr++;
363 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800364 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800365 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800366
367#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800368 {
369 /* Check if the level of dirs to strip off specified. */
370 char *tmp = getenv("GCOV_PREFIX_STRIP");
371 if (tmp) {
372 gcov_prefix_strip = atoi(tmp);
373 /* Do not consider negative values. */
374 if (gcov_prefix_strip < 0)
375 gcov_prefix_strip = 0;
376 }
377 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800378
Lee Leahye20a3192017-03-09 16:21:34 -0800379 /* Get file name relocation prefix. Non-absolute values are ignored. */
380 gcov_prefix = getenv("GCOV_PREFIX");
381 if (gcov_prefix) {
382 prefix_length = strlen(gcov_prefix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800383
Lee Leahye20a3192017-03-09 16:21:34 -0800384 /* Remove an unnecessary trailing '/' */
385 if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1]))
386 prefix_length--;
387 } else
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800388#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800389 prefix_length = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800390
Lee Leahye20a3192017-03-09 16:21:34 -0800391 /* If no prefix was specified and a prefix strip, then we assume
392 relative. */
393 if (gcov_prefix_strip != 0 && prefix_length == 0) {
394 gcov_prefix = ".";
395 prefix_length = 1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800396 }
Lee Leahye20a3192017-03-09 16:21:34 -0800397 /* Allocate and initialize the filename scratch space plus one. */
398 gi_filename = (char *) alloca(prefix_length + gcov_max_filename + 2);
399 if (prefix_length)
400 memcpy(gi_filename, gcov_prefix, prefix_length);
401 gi_filename_up = gi_filename + prefix_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800402
Lee Leahye20a3192017-03-09 16:21:34 -0800403 /* Now merge each file. */
404 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
405 unsigned int n_counts;
406 struct gcov_summary prg; /* summary for this object over all
407 program. */
408 struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
409 int error = 0;
410 gcov_unsigned_t tag, length;
411 gcov_position_t summary_pos = 0;
412 gcov_position_t eof_pos = 0;
413 const char *fname, *s;
Elyes HAOUAS1d3fde42018-06-05 08:41:29 +0200414 struct gcov_fn_buffer *fn_buffer = NULL;
Lee Leahye20a3192017-03-09 16:21:34 -0800415 struct gcov_fn_buffer **fn_tail = &fn_buffer;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800416
Lee Leahye20a3192017-03-09 16:21:34 -0800417 fname = gi_ptr->filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800418
Lee Leahye20a3192017-03-09 16:21:34 -0800419 /* Avoid to add multiple drive letters into combined path. */
420 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
421 fname += 2;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800422
Lee Leahye20a3192017-03-09 16:21:34 -0800423 /* Build relocated filename, stripping off leading
424 * directories from the initial filename if requested.
425 */
426 if (gcov_prefix_strip > 0) {
427 int level = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800428
Lee Leahye20a3192017-03-09 16:21:34 -0800429 s = fname;
430 if (IS_DIR_SEPARATOR(*s))
431 ++s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800432
Lee Leahye20a3192017-03-09 16:21:34 -0800433 /* Skip selected directory levels. */
434 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
435 if (IS_DIR_SEPARATOR(*s)) {
436 fname = s;
437 level++;
438 }
439 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800440
Lee Leahye20a3192017-03-09 16:21:34 -0800441 /* Update complete filename with stripped original. */
442 if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) {
443 /* If prefix is given, add directory separator.
444 */
445 strcpy(gi_filename_up, "/");
446 strcpy(gi_filename_up + 1, fname);
447 } else
448 strcpy(gi_filename_up, fname);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800449
Lee Leahye20a3192017-03-09 16:21:34 -0800450 if (!gcov_open(gi_filename)) {
451 /* Open failed likely due to missed directory.
452 * Create directory and retry to open file.
453 */
454 if (create_file_directory(gi_filename)) {
455 fprintf(stderr, "profiling:%s:Skip\n",
456 gi_filename);
457 continue;
458 }
459 if (!gcov_open(gi_filename)) {
460 fprintf(stderr,
461 "profiling:%s:Cannot open\n",
462 gi_filename);
463 continue;
464 }
465 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800466
Lee Leahye20a3192017-03-09 16:21:34 -0800467 tag = gcov_read_unsigned();
468 if (tag) {
469 /* Merge data from file. */
470 if (tag != GCOV_DATA_MAGIC) {
471 fprintf(stderr,
472 "profiling:%s:Not a gcov data file\n",
473 gi_filename);
474 goto read_fatal;
475 }
476 length = gcov_read_unsigned();
477 if (!gcov_version(gi_ptr, length, gi_filename))
478 goto read_fatal;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800479
Lee Leahye20a3192017-03-09 16:21:34 -0800480 length = gcov_read_unsigned();
481 if (length != gi_ptr->stamp)
482 /* Read from a different compilation.
483 * Overwrite the file.
484 */
485 goto rewrite;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800486
Lee Leahye20a3192017-03-09 16:21:34 -0800487 /* Look for program summary. */
488 for (f_ix = 0;;) {
489 struct gcov_summary tmp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800490
Lee Leahye20a3192017-03-09 16:21:34 -0800491 eof_pos = gcov_position();
492 tag = gcov_read_unsigned();
493 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
494 break;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800495
Lee Leahye20a3192017-03-09 16:21:34 -0800496 f_ix--;
497 length = gcov_read_unsigned();
498 if (length != GCOV_TAG_SUMMARY_LENGTH)
499 goto read_mismatch;
500 gcov_read_summary(&tmp);
Lee Leahy491c5b62017-03-10 15:51:04 -0800501 error = gcov_is_error();
502 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800503 goto read_error;
504 if (summary_pos
505 || tmp.checksum != crc32)
506 goto next_summary;
507
508 for (t_ix = 0; t_ix !=
509 GCOV_COUNTERS_SUMMABLE; t_ix++)
510 if (tmp.ctrs[t_ix].num !=
511 this_prg.ctrs[t_ix].num)
512 goto next_summary;
513 prg = tmp;
514 summary_pos = eof_pos;
515
516 next_summary:;
517 }
518
519 /* Merge execution counts for each function. */
520 for (f_ix = 0; (unsigned int)f_ix !=
521 gi_ptr->n_functions;
522 f_ix++, tag = gcov_read_unsigned()) {
523 gfi_ptr = gi_ptr->functions[f_ix];
524
525 if (tag != GCOV_TAG_FUNCTION)
526 goto read_mismatch;
527
528 length = gcov_read_unsigned();
529 if (!length)
530 /* This function did not appear
531 * in the other program. We
532 * have nothing to merge.
533 */
534 continue;
535
536 if (length != GCOV_TAG_FUNCTION_LENGTH)
537 goto read_mismatch;
538
539 if (!gfi_ptr || gfi_ptr->key !=
540 gi_ptr) {
541 /* This function appears in the
542 * other program. We need to
543 * buffer the information in
544 * order to write it back out --
545 * we'll be inserting data
546 * before this point, so cannot
547 * simply keep the data in the
548 * file.
549 */
550 fn_tail = buffer_fn_data(
551 gi_filename, gi_ptr,
552 fn_tail, f_ix);
553 if (!fn_tail)
554 goto read_mismatch;
555 continue;
556 }
557
558 length = gcov_read_unsigned();
559 if (length != gfi_ptr->ident)
560 goto read_mismatch;
561
562 length = gcov_read_unsigned();
563 if (length != gfi_ptr->lineno_checksum)
564 goto read_mismatch;
565
566 length = gcov_read_unsigned();
567 if (length != gfi_ptr->cfg_checksum)
568 goto read_mismatch;
569
570 ci_ptr = gfi_ptr->ctrs;
571 for (t_ix = 0; t_ix < GCOV_COUNTERS;
572 t_ix++) {
573 gcov_merge_fn merge =
574 gi_ptr->merge[t_ix];
575
576 if (!merge)
577 continue;
578
579 tag = gcov_read_unsigned();
580 length = gcov_read_unsigned();
581 if (tag != GCOV_TAG_FOR_COUNTER(
582 t_ix) || length !=
583 GCOV_TAG_COUNTER_LENGTH(
584 ci_ptr->num))
585 goto read_mismatch;
586 (*merge)(ci_ptr->values,
587 ci_ptr->num);
588 ci_ptr++;
589 }
Lee Leahy491c5b62017-03-10 15:51:04 -0800590 error = gcov_is_error();
591 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800592 goto read_error;
593 }
594
595 if (tag) {
596 read_mismatch:;
597 fprintf(stderr,
598 "profiling:%s:Merge mismatch for %s %u\n",
599 gi_filename, f_ix >= 0 ?
600 "function" : "summary",
601 f_ix < 0 ? -1 - f_ix : f_ix);
602 goto read_fatal;
603 }
604 }
605 goto rewrite;
606
607read_error:;
608 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
Lee Leahy35af5c42017-03-09 17:35:28 -0800609 error < 0 ? "Overflow" : "Error");
Lee Leahye20a3192017-03-09 16:21:34 -0800610
611 goto read_fatal;
612
613rewrite:;
614 gcov_rewrite();
615 if (!summary_pos) {
616 memset(&prg, 0, sizeof(prg));
617 summary_pos = eof_pos;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800618 }
619
Lee Leahye20a3192017-03-09 16:21:34 -0800620 /* Merge the summaries. */
621 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) {
622 cs_prg = &prg.ctrs[t_ix];
623 cs_tprg = &this_prg.ctrs[t_ix];
624 cs_all = &all_prg.ctrs[t_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800625
Lee Leahye20a3192017-03-09 16:21:34 -0800626 if (gi_ptr->merge[t_ix]) {
627 if (!cs_prg->runs++)
628 cs_prg->num = cs_tprg->num;
629 cs_prg->sum_all += cs_tprg->sum_all;
630 if (cs_prg->run_max < cs_tprg->run_max)
631 cs_prg->run_max = cs_tprg->run_max;
632 cs_prg->sum_max += cs_tprg->run_max;
633 } else if (cs_prg->runs)
634 goto read_mismatch;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800635
Lee Leahye20a3192017-03-09 16:21:34 -0800636 if (!cs_all->runs && cs_prg->runs)
637 memcpy(cs_all, cs_prg, sizeof(*cs_all));
638 else if (!all_prg.checksum
Lee Leahy73402172017-03-10 15:23:24 -0800639 && (!GCOV_LOCKED
640 || cs_all->runs == cs_prg->runs)
Lee Leahye20a3192017-03-09 16:21:34 -0800641 && memcmp(cs_all, cs_prg, sizeof(*cs_all))) {
642 fprintf(stderr,
643 "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
644 gi_filename, GCOV_LOCKED ? "" :
645 " or concurrently updated without locking support");
646 all_prg.checksum = ~0u;
647 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800648 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800649
Lee Leahye20a3192017-03-09 16:21:34 -0800650 prg.checksum = crc32;
651
652 /* Write out the data. */
653 if (!eof_pos) {
654 gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
655 gcov_write_unsigned(gi_ptr->stamp);
656 }
657
658 if (summary_pos)
659 gcov_seek(summary_pos);
660
661 /* Generate whole program statistics. */
662 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
663
664 if (summary_pos < eof_pos)
665 gcov_seek(eof_pos);
666
667 /* Write execution counts for each function. */
Lee Leahy73402172017-03-10 15:23:24 -0800668 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
669 f_ix++) {
Lee Leahye20a3192017-03-09 16:21:34 -0800670 unsigned int buffered = 0;
671
Lee Leahy73402172017-03-10 15:23:24 -0800672 if (fn_buffer && fn_buffer->fn_ix
673 == (unsigned int)f_ix) {
Lee Leahye20a3192017-03-09 16:21:34 -0800674 /* Buffered data from another program. */
675 buffered = 1;
676 gfi_ptr = &fn_buffer->info;
677 length = GCOV_TAG_FUNCTION_LENGTH;
678 } else {
679 gfi_ptr = gi_ptr->functions[f_ix];
680 if (gfi_ptr && gfi_ptr->key == gi_ptr)
681 length = GCOV_TAG_FUNCTION_LENGTH;
682 else
683 length = 0;
684 }
685
686 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
687 if (!length)
688 continue;
689
690 gcov_write_unsigned(gfi_ptr->ident);
691 gcov_write_unsigned(gfi_ptr->lineno_checksum);
692 gcov_write_unsigned(gfi_ptr->cfg_checksum);
693
694 ci_ptr = gfi_ptr->ctrs;
695 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) {
696 if (!gi_ptr->merge[t_ix])
697 continue;
698
699 n_counts = ci_ptr->num;
Lee Leahy73402172017-03-10 15:23:24 -0800700 gcov_write_tag_length(
701 GCOV_TAG_FOR_COUNTER(t_ix),
Lee Leahye20a3192017-03-09 16:21:34 -0800702 GCOV_TAG_COUNTER_LENGTH(n_counts));
703 gcov_type *c_ptr = ci_ptr->values;
704 while (n_counts--)
705 gcov_write_counter(*c_ptr++);
706 ci_ptr++;
707 }
708 if (buffered)
709 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
710 GCOV_COUNTERS);
711 }
712
713 gcov_write_unsigned(0);
714
715read_fatal:;
716 while (fn_buffer)
Lee Leahy73402172017-03-10 15:23:24 -0800717 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
718 GCOV_COUNTERS);
Lee Leahye20a3192017-03-09 16:21:34 -0800719
Lee Leahy491c5b62017-03-10 15:51:04 -0800720 error = gcov_close();
721 if (error)
Lee Leahye20a3192017-03-09 16:21:34 -0800722 fprintf(stderr, error < 0 ?
723 "profiling:%s:Overflow writing\n" :
724 "profiling:%s:Error writing\n",
725 gi_filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800726 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800727}
728
729/* Add a new object file onto the bb chain. Invoked automatically
730 when running an object file's global ctors. */
731
732void
Lee Leahy38768c32017-03-09 14:07:18 -0800733__gcov_init(struct gcov_info *info)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800734{
Lee Leahye20a3192017-03-09 16:21:34 -0800735 if (!info->version || !info->n_functions)
736 return;
737 if (gcov_version(info, info->version, 0)) {
738 size_t filename_length = strlen(info->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800739
Lee Leahye20a3192017-03-09 16:21:34 -0800740 /* Refresh the longest file name information */
741 if (filename_length > gcov_max_filename)
742 gcov_max_filename = filename_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800743
744#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800745 if (!gcov_list)
746 atexit(gcov_exit);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800747#endif
748
Lee Leahye20a3192017-03-09 16:21:34 -0800749 info->next = gcov_list;
750 gcov_list = info;
751 }
752 info->version = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800753}
754
755/* Called before fork or exec - write out profile information gathered so
756 far and reset it to zero. This avoids duplication or loss of the
757 profile information gathered so far. */
758
759void
Lee Leahy38768c32017-03-09 14:07:18 -0800760__gcov_flush(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800761{
Lee Leahye20a3192017-03-09 16:21:34 -0800762 const struct gcov_info *gi_ptr;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800763
Lee Leahye20a3192017-03-09 16:21:34 -0800764 gcov_exit();
765 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
766 unsigned int f_ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800767
Lee Leahye20a3192017-03-09 16:21:34 -0800768 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) {
769 unsigned int t_ix;
770 const struct gcov_fn_info *gfi_ptr =
771 gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800772
Lee Leahye20a3192017-03-09 16:21:34 -0800773 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
774 continue;
775 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
776 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) {
777 if (!gi_ptr->merge[t_ix])
778 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800779
Lee Leahye20a3192017-03-09 16:21:34 -0800780 memset(ci_ptr->values, 0,
781 sizeof(gcov_type) * ci_ptr->num);
782 ci_ptr++;
783 }
784 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800785 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800786}
787
788#endif /* L_gcov */
789
790#ifdef L_gcov_merge_add
791/* The profile merging function that just adds the counters. It is given
792 an array COUNTERS of N_COUNTERS old counters and it reads the same number
793 of counters from the gcov file. */
794void
Lee Leahy38768c32017-03-09 14:07:18 -0800795__gcov_merge_add(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800796{
Lee Leahye20a3192017-03-09 16:21:34 -0800797 for (; n_counters; counters++, n_counters--)
798 *counters += gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800799}
800#endif /* L_gcov_merge_add */
801
802#ifdef L_gcov_merge_ior
803/* The profile merging function that just adds the counters. It is given
804 an array COUNTERS of N_COUNTERS old counters and it reads the same number
805 of counters from the gcov file. */
806void
Lee Leahy38768c32017-03-09 14:07:18 -0800807__gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800808{
Lee Leahye20a3192017-03-09 16:21:34 -0800809 for (; n_counters; counters++, n_counters--)
810 *counters |= gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800811}
812#endif
813
814#ifdef L_gcov_merge_single
815/* The profile merging function for choosing the most common value.
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600816 * It is given an array COUNTERS of N_COUNTERS old counters and it
817 * reads the same number of counters from the gcov file. The counters
818 * are split into 3-tuples where the members of the tuple have
819 * meanings:
820 *
821 * -- the stored candidate on the most common value of the measured entity
822 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800823 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600824 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800825void
Lee Leahy38768c32017-03-09 14:07:18 -0800826__gcov_merge_single(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800827{
Lee Leahye20a3192017-03-09 16:21:34 -0800828 unsigned int i, n_measures;
829 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800830
Lee Leahye20a3192017-03-09 16:21:34 -0800831 gcc_assert(!(n_counters % 3));
832 n_measures = n_counters / 3;
833 for (i = 0; i < n_measures; i++, counters += 3) {
834 value = gcov_read_counter();
835 counter = gcov_read_counter();
836 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800837
Lee Leahye20a3192017-03-09 16:21:34 -0800838 if (counters[0] == value)
839 counters[1] += counter;
840 else if (counter > counters[1]) {
841 counters[0] = value;
842 counters[1] = counter - counters[1];
843 } else
844 counters[1] -= counter;
845 counters[2] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800846 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800847}
848#endif /* L_gcov_merge_single */
849
850#ifdef L_gcov_merge_delta
851/* The profile merging function for choosing the most common
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600852 * difference between two consecutive evaluations of the value. It is
853 * given an array COUNTERS of N_COUNTERS old counters and it reads the
854 * same number of counters from the gcov file. The counters are split
855 * into 4-tuples where the members of the tuple have meanings:
856 *
857 * -- the last value of the measured entity
858 * -- the stored candidate on the most common difference
859 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800860 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600861 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800862void
Lee Leahy38768c32017-03-09 14:07:18 -0800863__gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800864{
Lee Leahye20a3192017-03-09 16:21:34 -0800865 unsigned int i, n_measures;
866 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800867
Lee Leahye20a3192017-03-09 16:21:34 -0800868 gcc_assert(!(n_counters % 4));
869 n_measures = n_counters / 4;
870 for (i = 0; i < n_measures; i++, counters += 4) {
871 /* last = */
872 gcov_read_counter();
873 value = gcov_read_counter();
874 counter = gcov_read_counter();
875 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800876
Lee Leahye20a3192017-03-09 16:21:34 -0800877 if (counters[1] == value)
878 counters[2] += counter;
879 else if (counter > counters[2]) {
880 counters[1] = value;
881 counters[2] = counter - counters[2];
882 } else
883 counters[2] -= counter;
884 counters[3] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800885 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800886}
887#endif /* L_gcov_merge_delta */
888
889#ifdef L_gcov_interval_profiler
890/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
891 corresponding counter in COUNTERS. If the VALUE is above or below
892 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
893 instead. */
894
895void
Lee Leahy38768c32017-03-09 14:07:18 -0800896__gcov_interval_profiler(gcov_type *counters, gcov_type value,
Lee Leahy75b85992017-03-08 16:34:12 -0800897 int start, unsigned int steps)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800898{
Lee Leahye20a3192017-03-09 16:21:34 -0800899 gcov_type delta = value - start;
900 if (delta < 0)
901 counters[steps + 1]++;
902 else if (delta >= steps)
903 counters[steps]++;
904 else
905 counters[delta]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800906}
907#endif
908
909#ifdef L_gcov_pow2_profiler
910/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
911 COUNTERS[0] is incremented. */
912
913void
Lee Leahy38768c32017-03-09 14:07:18 -0800914__gcov_pow2_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800915{
Lee Leahye20a3192017-03-09 16:21:34 -0800916 if (value & (value - 1))
917 counters[0]++;
918 else
919 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800920}
921#endif
922
923/* Tries to determine the most common value among its inputs. Checks if the
924 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
925 is incremented. If this is not the case and COUNTERS[1] is not zero,
926 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
927 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
928 function is called more than 50% of the time with one value, this value
929 will be in COUNTERS[0] in the end.
930
931 In any case, COUNTERS[2] is incremented. */
932
933static inline void
Lee Leahy38768c32017-03-09 14:07:18 -0800934__gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800935{
Lee Leahye20a3192017-03-09 16:21:34 -0800936 if (value == counters[0])
937 counters[1]++;
938 else if (counters[1] == 0) {
939 counters[1] = 1;
940 counters[0] = value;
941 } else
942 counters[1]--;
943 counters[2]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800944}
945
946#ifdef L_gcov_one_value_profiler
947void
Lee Leahy38768c32017-03-09 14:07:18 -0800948__gcov_one_value_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800949{
Lee Leahye20a3192017-03-09 16:21:34 -0800950 __gcov_one_value_profiler_body(counters, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800951}
952#endif
953
954#ifdef L_gcov_indirect_call_profiler
955
956/* By default, the C++ compiler will use function addresses in the
957 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
958 tells the compiler to use function descriptors instead. The value
959 of this macro says how many words wide the descriptor is (normally 2),
960 but it may be dependent on target flags. Since we do not have access
961 to the target flags here we just check to see if it is set and use
962 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
963
964 It is assumed that the address of a function descriptor may be treated
965 as a pointer to a function. */
966
967#ifdef TARGET_VTABLE_USES_DESCRIPTORS
968#define VTABLE_USES_DESCRIPTORS 1
969#else
970#define VTABLE_USES_DESCRIPTORS 0
971#endif
972
973/* Tries to determine the most common value among its inputs. */
974void
Lee Leahy38768c32017-03-09 14:07:18 -0800975__gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
Lee Leahyb2d834a2017-03-08 16:52:22 -0800976 void *cur_func, void *callee_func)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800977{
Lee Leahye20a3192017-03-09 16:21:34 -0800978 /* If the C++ virtual tables contain function descriptors then one
979 * function may have multiple descriptors and we need to dereference
980 * the descriptors to see if they point to the same function.
981 */
982 if (cur_func == callee_func
983 || (VTABLE_USES_DESCRIPTORS && callee_func
984 && *(void **) cur_func == *(void **) callee_func))
985 __gcov_one_value_profiler_body(counter, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800986}
987#endif
988
989
990#ifdef L_gcov_average_profiler
991/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
992 to saturate up. */
993
994void
Lee Leahy38768c32017-03-09 14:07:18 -0800995__gcov_average_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800996{
Lee Leahye20a3192017-03-09 16:21:34 -0800997 counters[0] += value;
Lee Leahy35af5c42017-03-09 17:35:28 -0800998 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800999}
1000#endif
1001
1002#ifdef L_gcov_ior_profiler
1003/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
1004 to saturate up. */
1005
1006void
Lee Leahy38768c32017-03-09 14:07:18 -08001007__gcov_ior_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001008{
Lee Leahye20a3192017-03-09 16:21:34 -08001009 *counters |= value;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001010}
1011#endif
1012
1013#ifdef L_gcov_fork
1014/* A wrapper for the fork function. Flushes the accumulated profiling data, so
1015 that they are not counted twice. */
1016
1017pid_t
Lee Leahy38768c32017-03-09 14:07:18 -08001018__gcov_fork(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001019{
Lee Leahye20a3192017-03-09 16:21:34 -08001020 __gcov_flush();
1021 return fork();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001022}
1023#endif
1024
1025#ifdef L_gcov_execl
1026/* A wrapper for the execl function. Flushes the accumulated profiling data, so
1027 that they are not lost. */
1028
1029int
Lee Leahy38768c32017-03-09 14:07:18 -08001030__gcov_execl(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001031{
Lee Leahye20a3192017-03-09 16:21:34 -08001032 va_list ap, aq;
1033 unsigned int i, length;
1034 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001035
Lee Leahye20a3192017-03-09 16:21:34 -08001036 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001037
Lee Leahye20a3192017-03-09 16:21:34 -08001038 va_start(ap, arg);
1039 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001040
Lee Leahye20a3192017-03-09 16:21:34 -08001041 length = 2;
1042 while (va_arg(ap, char *))
1043 length++;
1044 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001045
Lee Leahye20a3192017-03-09 16:21:34 -08001046 args = (char **) alloca(length * sizeof(void *));
1047 args[0] = arg;
1048 for (i = 1; i < length; i++)
1049 args[i] = va_arg(aq, char *);
1050 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001051
Lee Leahye20a3192017-03-09 16:21:34 -08001052 return execv(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001053}
1054#endif
1055
1056#ifdef L_gcov_execlp
Lee Leahy73402172017-03-10 15:23:24 -08001057/* A wrapper for the execlp function. Flushes the accumulated profiling data,
1058 * so that they are not lost.
1059 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001060
1061int
Lee Leahy38768c32017-03-09 14:07:18 -08001062__gcov_execlp(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001063{
Lee Leahye20a3192017-03-09 16:21:34 -08001064 va_list ap, aq;
1065 unsigned int i, length;
1066 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001067
Lee Leahye20a3192017-03-09 16:21:34 -08001068 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001069
Lee Leahye20a3192017-03-09 16:21:34 -08001070 va_start(ap, arg);
1071 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001072
Lee Leahye20a3192017-03-09 16:21:34 -08001073 length = 2;
1074 while (va_arg(ap, char *))
1075 length++;
1076 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001077
Lee Leahye20a3192017-03-09 16:21:34 -08001078 args = (char **) alloca(length * sizeof(void *));
1079 args[0] = arg;
1080 for (i = 1; i < length; i++)
1081 args[i] = va_arg(aq, char *);
1082 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001083
Lee Leahye20a3192017-03-09 16:21:34 -08001084 return execvp(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001085}
1086#endif
1087
1088#ifdef L_gcov_execle
Lee Leahy73402172017-03-10 15:23:24 -08001089/* A wrapper for the execle function. Flushes the accumulated profiling data,
1090 * so that they are not lost.
1091 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001092
1093int
Lee Leahy38768c32017-03-09 14:07:18 -08001094__gcov_execle(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001095{
Lee Leahye20a3192017-03-09 16:21:34 -08001096 va_list ap, aq;
1097 unsigned int i, length;
1098 char **args;
1099 char **envp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001100
Lee Leahye20a3192017-03-09 16:21:34 -08001101 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001102
Lee Leahye20a3192017-03-09 16:21:34 -08001103 va_start(ap, arg);
1104 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001105
Lee Leahye20a3192017-03-09 16:21:34 -08001106 length = 2;
1107 while (va_arg(ap, char *))
1108 length++;
1109 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001110
Lee Leahye20a3192017-03-09 16:21:34 -08001111 args = (char **) alloca(length * sizeof(void *));
1112 args[0] = arg;
1113 for (i = 1; i < length; i++)
1114 args[i] = va_arg(aq, char *);
1115 envp = va_arg(aq, char **);
1116 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001117
Lee Leahye20a3192017-03-09 16:21:34 -08001118 return execve(path, args, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001119}
1120#endif
1121
1122#ifdef L_gcov_execv
1123/* A wrapper for the execv function. Flushes the accumulated profiling data, so
1124 that they are not lost. */
1125
1126int
Lee Leahy38768c32017-03-09 14:07:18 -08001127__gcov_execv(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001128{
Lee Leahye20a3192017-03-09 16:21:34 -08001129 __gcov_flush();
1130 return execv(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001131}
1132#endif
1133
1134#ifdef L_gcov_execvp
Lee Leahy73402172017-03-10 15:23:24 -08001135/* A wrapper for the execvp function. Flushes the accumulated profiling data,
1136 * so that they are not lost.
1137 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001138
1139int
Lee Leahy38768c32017-03-09 14:07:18 -08001140__gcov_execvp(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001141{
Lee Leahye20a3192017-03-09 16:21:34 -08001142 __gcov_flush();
1143 return execvp(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001144}
1145#endif
1146
1147#ifdef L_gcov_execve
Lee Leahy73402172017-03-10 15:23:24 -08001148/* A wrapper for the execve function. Flushes the accumulated profiling data,
1149 * so that they are not lost.
1150 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001151
1152int
Lee Leahy38768c32017-03-09 14:07:18 -08001153__gcov_execve(const char *path, char *const argv[], char *const envp[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001154{
Lee Leahye20a3192017-03-09 16:21:34 -08001155 __gcov_flush();
1156 return execve(path, argv, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001157}
1158#endif
1159#endif /* inhibit_libc */