blob: 2cfda0a364e047e7b82218add942cdef2bb00d0f [file] [log] [blame]
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001/* Routines required for instrumenting a program. */
2/* Compile this one with gcc. */
3/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010, 2011
5 Free Software Foundation, Inc.
6
7This file is part of GCC.
8
9GCC is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
11Software Foundation; either version 3, or (at your option) any later
12version.
13
14GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
18
19Under Section 7 of GPL version 3, you are granted additional
20permissions described in the GCC Runtime Library Exception, version
213.1, as published by the Free Software Foundation.
Patrick Georgia73b9312015-10-31 11:55:10 +010022*/
Stefan Reinauerd37ab452012-12-18 16:23:28 -080023
24#define __COREBOOT__
25#ifdef __COREBOOT__
26#include <stdlib.h>
27#include <string.h>
28#include <console/console.h>
29#include <assert.h>
30typedef s32 pid_t;
31#define gcc_assert(x) ASSERT(x)
32#define fprintf(file, x...) printk(BIOS_ERR, x)
Lee Leahy38768c32017-03-09 14:07:18 -080033#define alloca(size) __builtin_alloca(size)
Stefan Reinauerd37ab452012-12-18 16:23:28 -080034#include "gcov-glue.c"
35
36/* Define MACROs to be used by coreboot compilation. */
37# define L_gcov
38# define L_gcov_interval_profiler
39# define L_gcov_pow2_profiler
40# define L_gcov_one_value_profiler
41# define L_gcov_indirect_call_profiler
42# define L_gcov_average_profiler
43# define L_gcov_ior_profiler
44
45# define HAVE_CC_TLS 0
46# define __GCOV_KERNEL__
47
48# define IN_LIBGCOV 1
49# define IN_GCOV 0
50#else /* __COREBOOT__ */
51#include "tconfig.h"
52#include "tsystem.h"
53#include "coretypes.h"
54#include "tm.h"
55#include "libgcc_tm.h"
56#endif /* __COREBOOT__ */
57
58#ifndef __COREBOOT__
59#if defined(inhibit_libc)
60#define IN_LIBGCOV (-1)
61#else
62#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
63#include <stdio.h>
64#define IN_LIBGCOV 1
65#if defined(L_gcov)
66#define GCOV_LINKAGE /* nothing */
67#endif
68#endif
69#endif /* __COREBOOT__ */
70#include "gcov-io.h"
71
72#if defined(inhibit_libc)
73/* If libc and its header files are not available, provide dummy functions. */
74
75#ifdef L_gcov
Lee Leahy38768c32017-03-09 14:07:18 -080076void __gcov_init(struct gcov_info *p __attribute__ ((unused))) {}
77void __gcov_flush(void) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080078#endif
79
80#ifdef L_gcov_merge_add
Lee Leahy38768c32017-03-09 14:07:18 -080081void __gcov_merge_add(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080082 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080083#endif
84
85#ifdef L_gcov_merge_single
Lee Leahy38768c32017-03-09 14:07:18 -080086void __gcov_merge_single(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080087 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080088#endif
89
90#ifdef L_gcov_merge_delta
Lee Leahy38768c32017-03-09 14:07:18 -080091void __gcov_merge_delta(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -080092 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -080093#endif
94
95#else
96
97#ifndef __COREBOOT__
98#include <string.h>
99#if GCOV_LOCKED
100#include <fcntl.h>
101#include <errno.h>
102#include <sys/stat.h>
103#endif
104#else
105void __gcov_merge_add(gcov_type *counters __attribute__ ((unused)),
Lee Leahy75b85992017-03-08 16:34:12 -0800106 unsigned int n_counters __attribute__ ((unused))) {}
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800107#endif /* __COREBOOT__ */
108
109#ifdef L_gcov
110#include "gcov-io.c"
111
Lee Leahy342f8d62017-03-10 15:31:56 -0800112struct gcov_fn_buffer {
Lee Leahye20a3192017-03-09 16:21:34 -0800113 struct gcov_fn_buffer *next;
114 unsigned int fn_ix;
115 struct gcov_fn_info info;
116 /* note gcov_fn_info ends in a trailing array. */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800117};
118
119/* Chain of per-object gcov structures. */
120static struct gcov_info *gcov_list;
121
122/* Size of the longest file name. */
123static size_t gcov_max_filename = 0;
124
125/* Make sure path component of the given FILENAME exists, create
126 missing directories. FILENAME must be writable.
127 Returns zero on success, or -1 if an error occurred. */
128
129static int
Lee Leahy38768c32017-03-09 14:07:18 -0800130create_file_directory(char *filename)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800131{
132#ifdef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800133 (void) filename;
134 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800135#else
136#if !defined(TARGET_POSIX_IO) && !defined(_WIN32)
Lee Leahye20a3192017-03-09 16:21:34 -0800137 (void) filename;
138 return -1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800139#else
Lee Leahye20a3192017-03-09 16:21:34 -0800140 char *s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800141
Lee Leahye20a3192017-03-09 16:21:34 -0800142 s = filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800143
Lee Leahye20a3192017-03-09 16:21:34 -0800144 if (HAS_DRIVE_SPEC(s))
145 s += 2;
146 if (IS_DIR_SEPARATOR(*s))
147 ++s;
148 for (; *s != '\0'; s++)
149 if (IS_DIR_SEPARATOR(*s)) {
150 char sep = *s;
151 *s = '\0';
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800152
Lee Leahye20a3192017-03-09 16:21:34 -0800153 /* Try to make directory if it doesn't already exist. */
154 if (access(filename, F_OK) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800155#ifdef TARGET_POSIX_IO
Lee Leahye20a3192017-03-09 16:21:34 -0800156 && mkdir(filename, 0755) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800157#else
Lee Leahye20a3192017-03-09 16:21:34 -0800158 && mkdir(filename) == -1
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800159#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800160 /* The directory might have been made by another
161 * process.
162 */
163 && errno != EEXIST) {
164 fprintf(stderr,
165 "profiling:%s:Cannot create directory\n",
166 filename);
167 *s = sep;
168 return -1;
169 };
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800170
Lee Leahye20a3192017-03-09 16:21:34 -0800171 *s = sep;
172 };
173 return 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800174#endif
175#endif
176}
177
178static struct gcov_fn_buffer *
Lee Leahy38768c32017-03-09 14:07:18 -0800179free_fn_data(const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer,
Lee Leahy75b85992017-03-08 16:34:12 -0800180 unsigned int limit)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800181{
Lee Leahye20a3192017-03-09 16:21:34 -0800182 struct gcov_fn_buffer *next;
183 unsigned int ix, n_ctr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800184
Lee Leahye20a3192017-03-09 16:21:34 -0800185 if (!buffer)
186 return 0;
187 next = buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800188
Lee Leahye20a3192017-03-09 16:21:34 -0800189 for (ix = 0; ix != limit; ix++)
190 if (gi_ptr->merge[ix])
191 free(buffer->info.ctrs[n_ctr++].values);
192 free(buffer);
193 return next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800194}
195
196static struct gcov_fn_buffer **
Lee Leahy38768c32017-03-09 14:07:18 -0800197buffer_fn_data(const char *filename, const struct gcov_info *gi_ptr,
Lee Leahy75b85992017-03-08 16:34:12 -0800198 struct gcov_fn_buffer **end_ptr, unsigned int fn_ix)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800199{
Lee Leahye20a3192017-03-09 16:21:34 -0800200 unsigned int n_ctrs = 0, ix = 0;
201 struct gcov_fn_buffer *fn_buffer;
202 unsigned int len;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800203
Lee Leahye20a3192017-03-09 16:21:34 -0800204 for (ix = GCOV_COUNTERS; ix--;)
205 if (gi_ptr->merge[ix])
206 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800207
Lee Leahye20a3192017-03-09 16:21:34 -0800208 len = sizeof(*fn_buffer) + sizeof(fn_buffer->info.ctrs[0]) * n_ctrs;
209 fn_buffer = (struct gcov_fn_buffer *)malloc(len);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800210
Lee Leahye20a3192017-03-09 16:21:34 -0800211 if (!fn_buffer)
212 goto fail;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800213
Lee Leahye20a3192017-03-09 16:21:34 -0800214 fn_buffer->next = 0;
215 fn_buffer->fn_ix = fn_ix;
216 fn_buffer->info.ident = gcov_read_unsigned();
217 fn_buffer->info.lineno_checksum = gcov_read_unsigned();
218 fn_buffer->info.cfg_checksum = gcov_read_unsigned();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800219
Lee Leahye20a3192017-03-09 16:21:34 -0800220 for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++) {
221 gcov_unsigned_t length;
222 gcov_type *values;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800223
Lee Leahye20a3192017-03-09 16:21:34 -0800224 if (!gi_ptr->merge[ix])
225 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800226
Lee Leahye20a3192017-03-09 16:21:34 -0800227 if (gcov_read_unsigned() != GCOV_TAG_FOR_COUNTER(ix)) {
228 len = 0;
229 goto fail;
230 }
231
232 length = GCOV_TAG_COUNTER_NUM(gcov_read_unsigned());
233 len = length * sizeof(gcov_type);
234 values = (gcov_type *)malloc(len);
235 if (!values)
236 goto fail;
237
238 fn_buffer->info.ctrs[n_ctrs].num = length;
239 fn_buffer->info.ctrs[n_ctrs].values = values;
240
241 while (length--)
242 *values++ = gcov_read_counter();
243 n_ctrs++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800244 }
245
Lee Leahye20a3192017-03-09 16:21:34 -0800246 *end_ptr = fn_buffer;
247 return &fn_buffer->next;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800248
249fail:
Lee Leahy35af5c42017-03-09 17:35:28 -0800250 fprintf(stderr, "profiling:%s:Function %u %s %u\n", filename, fn_ix,
Lee Leahye20a3192017-03-09 16:21:34 -0800251 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800252
Lee Leahye20a3192017-03-09 16:21:34 -0800253 return (struct gcov_fn_buffer **)free_fn_data(gi_ptr, fn_buffer, ix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800254}
255
256/* Add an unsigned value to the current crc */
257
258static gcov_unsigned_t
Lee Leahy38768c32017-03-09 14:07:18 -0800259crc32_unsigned(gcov_unsigned_t crc32, gcov_unsigned_t value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800260{
Lee Leahye20a3192017-03-09 16:21:34 -0800261 unsigned int ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800262
Lee Leahye20a3192017-03-09 16:21:34 -0800263 for (ix = 32; ix--; value <<= 1) {
264 unsigned int feedback;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800265
Lee Leahye20a3192017-03-09 16:21:34 -0800266 feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
267 crc32 <<= 1;
268 crc32 ^= feedback;
269 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800270
Lee Leahye20a3192017-03-09 16:21:34 -0800271 return crc32;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800272}
273
274/* Check if VERSION of the info block PTR matches libgcov one.
275 Return 1 on success, or zero in case of versions mismatch.
276 If FILENAME is not NULL, its value used for reporting purposes
277 instead of value from the info block. */
278
279static int
Lee Leahy38768c32017-03-09 14:07:18 -0800280gcov_version(struct gcov_info *ptr, gcov_unsigned_t version,
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800281 const char *filename)
282{
Lee Leahye20a3192017-03-09 16:21:34 -0800283 if (version != GCOV_VERSION) {
284 char v[4], e[4];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800285
Lee Leahye20a3192017-03-09 16:21:34 -0800286 GCOV_UNSIGNED2STRING(v, version);
287 GCOV_UNSIGNED2STRING(e, GCOV_VERSION);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800288
Lee Leahye20a3192017-03-09 16:21:34 -0800289 fprintf(stderr,
290 "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
Lee Leahy35af5c42017-03-09 17:35:28 -0800291 filename ? filename : ptr->filename, e, v);
Lee Leahye20a3192017-03-09 16:21:34 -0800292 return 0;
293 }
294 return 1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800295}
296
297/* Dump the coverage counts. We merge with existing counts when
298 possible, to avoid growing the .da files ad infinitum. We use this
299 program's checksum to make sure we only accumulate whole program
300 statistics to the correct summary. An object file might be embedded
301 in two separate programs, and we must keep the two program
302 summaries separate. */
303
304static void
Lee Leahy38768c32017-03-09 14:07:18 -0800305gcov_exit(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800306{
Lee Leahye20a3192017-03-09 16:21:34 -0800307 struct gcov_info *gi_ptr;
308 const struct gcov_fn_info *gfi_ptr;
309 struct gcov_summary this_prg; /* summary for program. */
310 struct gcov_summary all_prg; /* summary for all instances of program. */
311 struct gcov_ctr_summary *cs_ptr;
312 const struct gcov_ctr_info *ci_ptr;
313 unsigned int t_ix;
314 int f_ix = 0;
315 gcov_unsigned_t c_num;
316 const char *gcov_prefix;
317 int gcov_prefix_strip = 0;
318 size_t prefix_length;
319 char *gi_filename, *gi_filename_up;
320 gcov_unsigned_t crc32 = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800321
Lee Leahye20a3192017-03-09 16:21:34 -0800322 memset(&all_prg, 0, sizeof(all_prg));
323 /* Find the totals for this execution. */
324 memset(&this_prg, 0, sizeof(this_prg));
325 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
326 crc32 = crc32_unsigned(crc32, gi_ptr->stamp);
327 crc32 = crc32_unsigned(crc32, gi_ptr->n_functions);
Kyösti Mälkkiecd84242013-09-13 07:57:49 +0300328
Lee Leahye20a3192017-03-09 16:21:34 -0800329 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
330 f_ix++) {
331 gfi_ptr = gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800332
Lee Leahye20a3192017-03-09 16:21:34 -0800333 if (gfi_ptr && gfi_ptr->key != gi_ptr)
334 gfi_ptr = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800335
Lee Leahye20a3192017-03-09 16:21:34 -0800336 crc32 = crc32_unsigned(crc32, gfi_ptr
337 ? gfi_ptr->cfg_checksum : 0);
338 crc32 = crc32_unsigned(crc32,
339 gfi_ptr ? gfi_ptr->lineno_checksum : 0);
340 if (!gfi_ptr)
341 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800342
Lee Leahye20a3192017-03-09 16:21:34 -0800343 ci_ptr = gfi_ptr->ctrs;
344 for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) {
345 if (!gi_ptr->merge[t_ix])
346 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800347
Lee Leahye20a3192017-03-09 16:21:34 -0800348 cs_ptr = &this_prg.ctrs[t_ix];
349 cs_ptr->num += ci_ptr->num;
350 crc32 = crc32_unsigned(crc32, ci_ptr->num);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800351
Lee Leahye20a3192017-03-09 16:21:34 -0800352 for (c_num = 0; c_num < ci_ptr->num; c_num++) {
353 cs_ptr->sum_all +=
354 ci_ptr->values[c_num];
355 if (cs_ptr->run_max
356 < ci_ptr->values[c_num])
357 cs_ptr->run_max =
358 ci_ptr->values[c_num];
359 }
360 ci_ptr++;
361 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800362 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800363 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800364
365#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800366 {
367 /* Check if the level of dirs to strip off specified. */
368 char *tmp = getenv("GCOV_PREFIX_STRIP");
369 if (tmp) {
370 gcov_prefix_strip = atoi(tmp);
371 /* Do not consider negative values. */
372 if (gcov_prefix_strip < 0)
373 gcov_prefix_strip = 0;
374 }
375 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800376
Lee Leahye20a3192017-03-09 16:21:34 -0800377 /* Get file name relocation prefix. Non-absolute values are ignored. */
378 gcov_prefix = getenv("GCOV_PREFIX");
379 if (gcov_prefix) {
380 prefix_length = strlen(gcov_prefix);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800381
Lee Leahye20a3192017-03-09 16:21:34 -0800382 /* Remove an unnecessary trailing '/' */
383 if (IS_DIR_SEPARATOR(gcov_prefix[prefix_length - 1]))
384 prefix_length--;
385 } else
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800386#endif
Lee Leahye20a3192017-03-09 16:21:34 -0800387 prefix_length = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800388
Lee Leahye20a3192017-03-09 16:21:34 -0800389 /* If no prefix was specified and a prefix strip, then we assume
390 relative. */
391 if (gcov_prefix_strip != 0 && prefix_length == 0) {
392 gcov_prefix = ".";
393 prefix_length = 1;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800394 }
Lee Leahye20a3192017-03-09 16:21:34 -0800395 /* Allocate and initialize the filename scratch space plus one. */
396 gi_filename = (char *) alloca(prefix_length + gcov_max_filename + 2);
397 if (prefix_length)
398 memcpy(gi_filename, gcov_prefix, prefix_length);
399 gi_filename_up = gi_filename + prefix_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800400
Lee Leahye20a3192017-03-09 16:21:34 -0800401 /* Now merge each file. */
402 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
403 unsigned int n_counts;
404 struct gcov_summary prg; /* summary for this object over all
405 program. */
406 struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
407 int error = 0;
408 gcov_unsigned_t tag, length;
409 gcov_position_t summary_pos = 0;
410 gcov_position_t eof_pos = 0;
411 const char *fname, *s;
412 struct gcov_fn_buffer *fn_buffer = 0;
413 struct gcov_fn_buffer **fn_tail = &fn_buffer;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800414
Lee Leahye20a3192017-03-09 16:21:34 -0800415 fname = gi_ptr->filename;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800416
Lee Leahye20a3192017-03-09 16:21:34 -0800417 /* Avoid to add multiple drive letters into combined path. */
418 if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
419 fname += 2;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800420
Lee Leahye20a3192017-03-09 16:21:34 -0800421 /* Build relocated filename, stripping off leading
422 * directories from the initial filename if requested.
423 */
424 if (gcov_prefix_strip > 0) {
425 int level = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800426
Lee Leahye20a3192017-03-09 16:21:34 -0800427 s = fname;
428 if (IS_DIR_SEPARATOR(*s))
429 ++s;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800430
Lee Leahye20a3192017-03-09 16:21:34 -0800431 /* Skip selected directory levels. */
432 for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
433 if (IS_DIR_SEPARATOR(*s)) {
434 fname = s;
435 level++;
436 }
437 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800438
Lee Leahye20a3192017-03-09 16:21:34 -0800439 /* Update complete filename with stripped original. */
440 if (prefix_length != 0 && !IS_DIR_SEPARATOR(*fname)) {
441 /* If prefix is given, add directory separator.
442 */
443 strcpy(gi_filename_up, "/");
444 strcpy(gi_filename_up + 1, fname);
445 } else
446 strcpy(gi_filename_up, fname);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800447
Lee Leahye20a3192017-03-09 16:21:34 -0800448 if (!gcov_open(gi_filename)) {
449 /* Open failed likely due to missed directory.
450 * Create directory and retry to open file.
451 */
452 if (create_file_directory(gi_filename)) {
453 fprintf(stderr, "profiling:%s:Skip\n",
454 gi_filename);
455 continue;
456 }
457 if (!gcov_open(gi_filename)) {
458 fprintf(stderr,
459 "profiling:%s:Cannot open\n",
460 gi_filename);
461 continue;
462 }
463 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800464
Lee Leahye20a3192017-03-09 16:21:34 -0800465 tag = gcov_read_unsigned();
466 if (tag) {
467 /* Merge data from file. */
468 if (tag != GCOV_DATA_MAGIC) {
469 fprintf(stderr,
470 "profiling:%s:Not a gcov data file\n",
471 gi_filename);
472 goto read_fatal;
473 }
474 length = gcov_read_unsigned();
475 if (!gcov_version(gi_ptr, length, gi_filename))
476 goto read_fatal;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800477
Lee Leahye20a3192017-03-09 16:21:34 -0800478 length = gcov_read_unsigned();
479 if (length != gi_ptr->stamp)
480 /* Read from a different compilation.
481 * Overwrite the file.
482 */
483 goto rewrite;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800484
Lee Leahye20a3192017-03-09 16:21:34 -0800485 /* Look for program summary. */
486 for (f_ix = 0;;) {
487 struct gcov_summary tmp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800488
Lee Leahye20a3192017-03-09 16:21:34 -0800489 eof_pos = gcov_position();
490 tag = gcov_read_unsigned();
491 if (tag != GCOV_TAG_PROGRAM_SUMMARY)
492 break;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800493
Lee Leahye20a3192017-03-09 16:21:34 -0800494 f_ix--;
495 length = gcov_read_unsigned();
496 if (length != GCOV_TAG_SUMMARY_LENGTH)
497 goto read_mismatch;
498 gcov_read_summary(&tmp);
499 if ((error = gcov_is_error()))
500 goto read_error;
501 if (summary_pos
502 || tmp.checksum != crc32)
503 goto next_summary;
504
505 for (t_ix = 0; t_ix !=
506 GCOV_COUNTERS_SUMMABLE; t_ix++)
507 if (tmp.ctrs[t_ix].num !=
508 this_prg.ctrs[t_ix].num)
509 goto next_summary;
510 prg = tmp;
511 summary_pos = eof_pos;
512
513 next_summary:;
514 }
515
516 /* Merge execution counts for each function. */
517 for (f_ix = 0; (unsigned int)f_ix !=
518 gi_ptr->n_functions;
519 f_ix++, tag = gcov_read_unsigned()) {
520 gfi_ptr = gi_ptr->functions[f_ix];
521
522 if (tag != GCOV_TAG_FUNCTION)
523 goto read_mismatch;
524
525 length = gcov_read_unsigned();
526 if (!length)
527 /* This function did not appear
528 * in the other program. We
529 * have nothing to merge.
530 */
531 continue;
532
533 if (length != GCOV_TAG_FUNCTION_LENGTH)
534 goto read_mismatch;
535
536 if (!gfi_ptr || gfi_ptr->key !=
537 gi_ptr) {
538 /* This function appears in the
539 * other program. We need to
540 * buffer the information in
541 * order to write it back out --
542 * we'll be inserting data
543 * before this point, so cannot
544 * simply keep the data in the
545 * file.
546 */
547 fn_tail = buffer_fn_data(
548 gi_filename, gi_ptr,
549 fn_tail, f_ix);
550 if (!fn_tail)
551 goto read_mismatch;
552 continue;
553 }
554
555 length = gcov_read_unsigned();
556 if (length != gfi_ptr->ident)
557 goto read_mismatch;
558
559 length = gcov_read_unsigned();
560 if (length != gfi_ptr->lineno_checksum)
561 goto read_mismatch;
562
563 length = gcov_read_unsigned();
564 if (length != gfi_ptr->cfg_checksum)
565 goto read_mismatch;
566
567 ci_ptr = gfi_ptr->ctrs;
568 for (t_ix = 0; t_ix < GCOV_COUNTERS;
569 t_ix++) {
570 gcov_merge_fn merge =
571 gi_ptr->merge[t_ix];
572
573 if (!merge)
574 continue;
575
576 tag = gcov_read_unsigned();
577 length = gcov_read_unsigned();
578 if (tag != GCOV_TAG_FOR_COUNTER(
579 t_ix) || length !=
580 GCOV_TAG_COUNTER_LENGTH(
581 ci_ptr->num))
582 goto read_mismatch;
583 (*merge)(ci_ptr->values,
584 ci_ptr->num);
585 ci_ptr++;
586 }
587 if ((error = gcov_is_error()))
588 goto read_error;
589 }
590
591 if (tag) {
592 read_mismatch:;
593 fprintf(stderr,
594 "profiling:%s:Merge mismatch for %s %u\n",
595 gi_filename, f_ix >= 0 ?
596 "function" : "summary",
597 f_ix < 0 ? -1 - f_ix : f_ix);
598 goto read_fatal;
599 }
600 }
601 goto rewrite;
602
603read_error:;
604 fprintf(stderr, "profiling:%s:%s merging\n", gi_filename,
Lee Leahy35af5c42017-03-09 17:35:28 -0800605 error < 0 ? "Overflow" : "Error");
Lee Leahye20a3192017-03-09 16:21:34 -0800606
607 goto read_fatal;
608
609rewrite:;
610 gcov_rewrite();
611 if (!summary_pos) {
612 memset(&prg, 0, sizeof(prg));
613 summary_pos = eof_pos;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800614 }
615
Lee Leahye20a3192017-03-09 16:21:34 -0800616 /* Merge the summaries. */
617 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) {
618 cs_prg = &prg.ctrs[t_ix];
619 cs_tprg = &this_prg.ctrs[t_ix];
620 cs_all = &all_prg.ctrs[t_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800621
Lee Leahye20a3192017-03-09 16:21:34 -0800622 if (gi_ptr->merge[t_ix]) {
623 if (!cs_prg->runs++)
624 cs_prg->num = cs_tprg->num;
625 cs_prg->sum_all += cs_tprg->sum_all;
626 if (cs_prg->run_max < cs_tprg->run_max)
627 cs_prg->run_max = cs_tprg->run_max;
628 cs_prg->sum_max += cs_tprg->run_max;
629 } else if (cs_prg->runs)
630 goto read_mismatch;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800631
Lee Leahye20a3192017-03-09 16:21:34 -0800632 if (!cs_all->runs && cs_prg->runs)
633 memcpy(cs_all, cs_prg, sizeof(*cs_all));
634 else if (!all_prg.checksum
Lee Leahy73402172017-03-10 15:23:24 -0800635 && (!GCOV_LOCKED
636 || cs_all->runs == cs_prg->runs)
Lee Leahye20a3192017-03-09 16:21:34 -0800637 && memcmp(cs_all, cs_prg, sizeof(*cs_all))) {
638 fprintf(stderr,
639 "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
640 gi_filename, GCOV_LOCKED ? "" :
641 " or concurrently updated without locking support");
642 all_prg.checksum = ~0u;
643 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800644 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800645
Lee Leahye20a3192017-03-09 16:21:34 -0800646 prg.checksum = crc32;
647
648 /* Write out the data. */
649 if (!eof_pos) {
650 gcov_write_tag_length(GCOV_DATA_MAGIC, GCOV_VERSION);
651 gcov_write_unsigned(gi_ptr->stamp);
652 }
653
654 if (summary_pos)
655 gcov_seek(summary_pos);
656
657 /* Generate whole program statistics. */
658 gcov_write_summary(GCOV_TAG_PROGRAM_SUMMARY, &prg);
659
660 if (summary_pos < eof_pos)
661 gcov_seek(eof_pos);
662
663 /* Write execution counts for each function. */
Lee Leahy73402172017-03-10 15:23:24 -0800664 for (f_ix = 0; (unsigned int)f_ix != gi_ptr->n_functions;
665 f_ix++) {
Lee Leahye20a3192017-03-09 16:21:34 -0800666 unsigned int buffered = 0;
667
Lee Leahy73402172017-03-10 15:23:24 -0800668 if (fn_buffer && fn_buffer->fn_ix
669 == (unsigned int)f_ix) {
Lee Leahye20a3192017-03-09 16:21:34 -0800670 /* Buffered data from another program. */
671 buffered = 1;
672 gfi_ptr = &fn_buffer->info;
673 length = GCOV_TAG_FUNCTION_LENGTH;
674 } else {
675 gfi_ptr = gi_ptr->functions[f_ix];
676 if (gfi_ptr && gfi_ptr->key == gi_ptr)
677 length = GCOV_TAG_FUNCTION_LENGTH;
678 else
679 length = 0;
680 }
681
682 gcov_write_tag_length(GCOV_TAG_FUNCTION, length);
683 if (!length)
684 continue;
685
686 gcov_write_unsigned(gfi_ptr->ident);
687 gcov_write_unsigned(gfi_ptr->lineno_checksum);
688 gcov_write_unsigned(gfi_ptr->cfg_checksum);
689
690 ci_ptr = gfi_ptr->ctrs;
691 for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) {
692 if (!gi_ptr->merge[t_ix])
693 continue;
694
695 n_counts = ci_ptr->num;
Lee Leahy73402172017-03-10 15:23:24 -0800696 gcov_write_tag_length(
697 GCOV_TAG_FOR_COUNTER(t_ix),
Lee Leahye20a3192017-03-09 16:21:34 -0800698 GCOV_TAG_COUNTER_LENGTH(n_counts));
699 gcov_type *c_ptr = ci_ptr->values;
700 while (n_counts--)
701 gcov_write_counter(*c_ptr++);
702 ci_ptr++;
703 }
704 if (buffered)
705 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
706 GCOV_COUNTERS);
707 }
708
709 gcov_write_unsigned(0);
710
711read_fatal:;
712 while (fn_buffer)
Lee Leahy73402172017-03-10 15:23:24 -0800713 fn_buffer = free_fn_data(gi_ptr, fn_buffer,
714 GCOV_COUNTERS);
Lee Leahye20a3192017-03-09 16:21:34 -0800715
716 if ((error = gcov_close()))
717 fprintf(stderr, error < 0 ?
718 "profiling:%s:Overflow writing\n" :
719 "profiling:%s:Error writing\n",
720 gi_filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800721 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800722}
723
724/* Add a new object file onto the bb chain. Invoked automatically
725 when running an object file's global ctors. */
726
727void
Lee Leahy38768c32017-03-09 14:07:18 -0800728__gcov_init(struct gcov_info *info)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800729{
Lee Leahye20a3192017-03-09 16:21:34 -0800730 if (!info->version || !info->n_functions)
731 return;
732 if (gcov_version(info, info->version, 0)) {
733 size_t filename_length = strlen(info->filename);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800734
Lee Leahye20a3192017-03-09 16:21:34 -0800735 /* Refresh the longest file name information */
736 if (filename_length > gcov_max_filename)
737 gcov_max_filename = filename_length;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800738
739#ifndef __COREBOOT__
Lee Leahye20a3192017-03-09 16:21:34 -0800740 if (!gcov_list)
741 atexit(gcov_exit);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800742#endif
743
Lee Leahye20a3192017-03-09 16:21:34 -0800744 info->next = gcov_list;
745 gcov_list = info;
746 }
747 info->version = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800748}
749
750/* Called before fork or exec - write out profile information gathered so
751 far and reset it to zero. This avoids duplication or loss of the
752 profile information gathered so far. */
753
754void
Lee Leahy38768c32017-03-09 14:07:18 -0800755__gcov_flush(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800756{
Lee Leahye20a3192017-03-09 16:21:34 -0800757 const struct gcov_info *gi_ptr;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800758
Lee Leahye20a3192017-03-09 16:21:34 -0800759 gcov_exit();
760 for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) {
761 unsigned int f_ix;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800762
Lee Leahye20a3192017-03-09 16:21:34 -0800763 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) {
764 unsigned int t_ix;
765 const struct gcov_fn_info *gfi_ptr =
766 gi_ptr->functions[f_ix];
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800767
Lee Leahye20a3192017-03-09 16:21:34 -0800768 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
769 continue;
770 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
771 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) {
772 if (!gi_ptr->merge[t_ix])
773 continue;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800774
Lee Leahye20a3192017-03-09 16:21:34 -0800775 memset(ci_ptr->values, 0,
776 sizeof(gcov_type) * ci_ptr->num);
777 ci_ptr++;
778 }
779 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800780 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800781}
782
783#endif /* L_gcov */
784
785#ifdef L_gcov_merge_add
786/* The profile merging function that just adds the counters. It is given
787 an array COUNTERS of N_COUNTERS old counters and it reads the same number
788 of counters from the gcov file. */
789void
Lee Leahy38768c32017-03-09 14:07:18 -0800790__gcov_merge_add(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800791{
Lee Leahye20a3192017-03-09 16:21:34 -0800792 for (; n_counters; counters++, n_counters--)
793 *counters += gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800794}
795#endif /* L_gcov_merge_add */
796
797#ifdef L_gcov_merge_ior
798/* The profile merging function that just adds the counters. It is given
799 an array COUNTERS of N_COUNTERS old counters and it reads the same number
800 of counters from the gcov file. */
801void
Lee Leahy38768c32017-03-09 14:07:18 -0800802__gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800803{
Lee Leahye20a3192017-03-09 16:21:34 -0800804 for (; n_counters; counters++, n_counters--)
805 *counters |= gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800806}
807#endif
808
809#ifdef L_gcov_merge_single
810/* The profile merging function for choosing the most common value.
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600811 * It is given an array COUNTERS of N_COUNTERS old counters and it
812 * reads the same number of counters from the gcov file. The counters
813 * are split into 3-tuples where the members of the tuple have
814 * meanings:
815 *
816 * -- the stored candidate on the most common value of the measured entity
817 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800818 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600819 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800820void
Lee Leahy38768c32017-03-09 14:07:18 -0800821__gcov_merge_single(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800822{
Lee Leahye20a3192017-03-09 16:21:34 -0800823 unsigned int i, n_measures;
824 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800825
Lee Leahye20a3192017-03-09 16:21:34 -0800826 gcc_assert(!(n_counters % 3));
827 n_measures = n_counters / 3;
828 for (i = 0; i < n_measures; i++, counters += 3) {
829 value = gcov_read_counter();
830 counter = gcov_read_counter();
831 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800832
Lee Leahye20a3192017-03-09 16:21:34 -0800833 if (counters[0] == value)
834 counters[1] += counter;
835 else if (counter > counters[1]) {
836 counters[0] = value;
837 counters[1] = counter - counters[1];
838 } else
839 counters[1] -= counter;
840 counters[2] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800841 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800842}
843#endif /* L_gcov_merge_single */
844
845#ifdef L_gcov_merge_delta
846/* The profile merging function for choosing the most common
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600847 * difference between two consecutive evaluations of the value. It is
848 * given an array COUNTERS of N_COUNTERS old counters and it reads the
849 * same number of counters from the gcov file. The counters are split
850 * into 4-tuples where the members of the tuple have meanings:
851 *
852 * -- the last value of the measured entity
853 * -- the stored candidate on the most common difference
854 * -- counter
Stefan Reinauerf572e1e2013-01-16 09:47:54 -0800855 * -- total number of evaluations of the value
Ronald G. Minnich850793f2013-01-13 17:22:42 -0600856 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800857void
Lee Leahy38768c32017-03-09 14:07:18 -0800858__gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800859{
Lee Leahye20a3192017-03-09 16:21:34 -0800860 unsigned int i, n_measures;
861 gcov_type value, counter, all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800862
Lee Leahye20a3192017-03-09 16:21:34 -0800863 gcc_assert(!(n_counters % 4));
864 n_measures = n_counters / 4;
865 for (i = 0; i < n_measures; i++, counters += 4) {
866 /* last = */
867 gcov_read_counter();
868 value = gcov_read_counter();
869 counter = gcov_read_counter();
870 all = gcov_read_counter();
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800871
Lee Leahye20a3192017-03-09 16:21:34 -0800872 if (counters[1] == value)
873 counters[2] += counter;
874 else if (counter > counters[2]) {
875 counters[1] = value;
876 counters[2] = counter - counters[2];
877 } else
878 counters[2] -= counter;
879 counters[3] += all;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800880 }
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800881}
882#endif /* L_gcov_merge_delta */
883
884#ifdef L_gcov_interval_profiler
885/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
886 corresponding counter in COUNTERS. If the VALUE is above or below
887 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
888 instead. */
889
890void
Lee Leahy38768c32017-03-09 14:07:18 -0800891__gcov_interval_profiler(gcov_type *counters, gcov_type value,
Lee Leahy75b85992017-03-08 16:34:12 -0800892 int start, unsigned int steps)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800893{
Lee Leahye20a3192017-03-09 16:21:34 -0800894 gcov_type delta = value - start;
895 if (delta < 0)
896 counters[steps + 1]++;
897 else if (delta >= steps)
898 counters[steps]++;
899 else
900 counters[delta]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800901}
902#endif
903
904#ifdef L_gcov_pow2_profiler
905/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
906 COUNTERS[0] is incremented. */
907
908void
Lee Leahy38768c32017-03-09 14:07:18 -0800909__gcov_pow2_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800910{
Lee Leahye20a3192017-03-09 16:21:34 -0800911 if (value & (value - 1))
912 counters[0]++;
913 else
914 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800915}
916#endif
917
918/* Tries to determine the most common value among its inputs. Checks if the
919 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1]
920 is incremented. If this is not the case and COUNTERS[1] is not zero,
921 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and
922 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this
923 function is called more than 50% of the time with one value, this value
924 will be in COUNTERS[0] in the end.
925
926 In any case, COUNTERS[2] is incremented. */
927
928static inline void
Lee Leahy38768c32017-03-09 14:07:18 -0800929__gcov_one_value_profiler_body(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800930{
Lee Leahye20a3192017-03-09 16:21:34 -0800931 if (value == counters[0])
932 counters[1]++;
933 else if (counters[1] == 0) {
934 counters[1] = 1;
935 counters[0] = value;
936 } else
937 counters[1]--;
938 counters[2]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800939}
940
941#ifdef L_gcov_one_value_profiler
942void
Lee Leahy38768c32017-03-09 14:07:18 -0800943__gcov_one_value_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800944{
Lee Leahye20a3192017-03-09 16:21:34 -0800945 __gcov_one_value_profiler_body(counters, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800946}
947#endif
948
949#ifdef L_gcov_indirect_call_profiler
950
951/* By default, the C++ compiler will use function addresses in the
952 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
953 tells the compiler to use function descriptors instead. The value
954 of this macro says how many words wide the descriptor is (normally 2),
955 but it may be dependent on target flags. Since we do not have access
956 to the target flags here we just check to see if it is set and use
957 that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
958
959 It is assumed that the address of a function descriptor may be treated
960 as a pointer to a function. */
961
962#ifdef TARGET_VTABLE_USES_DESCRIPTORS
963#define VTABLE_USES_DESCRIPTORS 1
964#else
965#define VTABLE_USES_DESCRIPTORS 0
966#endif
967
968/* Tries to determine the most common value among its inputs. */
969void
Lee Leahy38768c32017-03-09 14:07:18 -0800970__gcov_indirect_call_profiler(gcov_type *counter, gcov_type value,
Lee Leahyb2d834a2017-03-08 16:52:22 -0800971 void *cur_func, void *callee_func)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800972{
Lee Leahye20a3192017-03-09 16:21:34 -0800973 /* If the C++ virtual tables contain function descriptors then one
974 * function may have multiple descriptors and we need to dereference
975 * the descriptors to see if they point to the same function.
976 */
977 if (cur_func == callee_func
978 || (VTABLE_USES_DESCRIPTORS && callee_func
979 && *(void **) cur_func == *(void **) callee_func))
980 __gcov_one_value_profiler_body(counter, value);
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800981}
982#endif
983
984
985#ifdef L_gcov_average_profiler
986/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
987 to saturate up. */
988
989void
Lee Leahy38768c32017-03-09 14:07:18 -0800990__gcov_average_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800991{
Lee Leahye20a3192017-03-09 16:21:34 -0800992 counters[0] += value;
Lee Leahy35af5c42017-03-09 17:35:28 -0800993 counters[1]++;
Stefan Reinauerd37ab452012-12-18 16:23:28 -0800994}
995#endif
996
997#ifdef L_gcov_ior_profiler
998/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
999 to saturate up. */
1000
1001void
Lee Leahy38768c32017-03-09 14:07:18 -08001002__gcov_ior_profiler(gcov_type *counters, gcov_type value)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001003{
Lee Leahye20a3192017-03-09 16:21:34 -08001004 *counters |= value;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001005}
1006#endif
1007
1008#ifdef L_gcov_fork
1009/* A wrapper for the fork function. Flushes the accumulated profiling data, so
1010 that they are not counted twice. */
1011
1012pid_t
Lee Leahy38768c32017-03-09 14:07:18 -08001013__gcov_fork(void)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001014{
Lee Leahye20a3192017-03-09 16:21:34 -08001015 __gcov_flush();
1016 return fork();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001017}
1018#endif
1019
1020#ifdef L_gcov_execl
1021/* A wrapper for the execl function. Flushes the accumulated profiling data, so
1022 that they are not lost. */
1023
1024int
Lee Leahy38768c32017-03-09 14:07:18 -08001025__gcov_execl(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001026{
Lee Leahye20a3192017-03-09 16:21:34 -08001027 va_list ap, aq;
1028 unsigned int i, length;
1029 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001030
Lee Leahye20a3192017-03-09 16:21:34 -08001031 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001032
Lee Leahye20a3192017-03-09 16:21:34 -08001033 va_start(ap, arg);
1034 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001035
Lee Leahye20a3192017-03-09 16:21:34 -08001036 length = 2;
1037 while (va_arg(ap, char *))
1038 length++;
1039 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001040
Lee Leahye20a3192017-03-09 16:21:34 -08001041 args = (char **) alloca(length * sizeof(void *));
1042 args[0] = arg;
1043 for (i = 1; i < length; i++)
1044 args[i] = va_arg(aq, char *);
1045 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001046
Lee Leahye20a3192017-03-09 16:21:34 -08001047 return execv(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001048}
1049#endif
1050
1051#ifdef L_gcov_execlp
Lee Leahy73402172017-03-10 15:23:24 -08001052/* A wrapper for the execlp function. Flushes the accumulated profiling data,
1053 * so that they are not lost.
1054 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001055
1056int
Lee Leahy38768c32017-03-09 14:07:18 -08001057__gcov_execlp(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001058{
Lee Leahye20a3192017-03-09 16:21:34 -08001059 va_list ap, aq;
1060 unsigned int i, length;
1061 char **args;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001062
Lee Leahye20a3192017-03-09 16:21:34 -08001063 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001064
Lee Leahye20a3192017-03-09 16:21:34 -08001065 va_start(ap, arg);
1066 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001067
Lee Leahye20a3192017-03-09 16:21:34 -08001068 length = 2;
1069 while (va_arg(ap, char *))
1070 length++;
1071 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001072
Lee Leahye20a3192017-03-09 16:21:34 -08001073 args = (char **) alloca(length * sizeof(void *));
1074 args[0] = arg;
1075 for (i = 1; i < length; i++)
1076 args[i] = va_arg(aq, char *);
1077 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001078
Lee Leahye20a3192017-03-09 16:21:34 -08001079 return execvp(path, args);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001080}
1081#endif
1082
1083#ifdef L_gcov_execle
Lee Leahy73402172017-03-10 15:23:24 -08001084/* A wrapper for the execle function. Flushes the accumulated profiling data,
1085 * so that they are not lost.
1086 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001087
1088int
Lee Leahy38768c32017-03-09 14:07:18 -08001089__gcov_execle(const char *path, char *arg, ...)
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001090{
Lee Leahye20a3192017-03-09 16:21:34 -08001091 va_list ap, aq;
1092 unsigned int i, length;
1093 char **args;
1094 char **envp;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001095
Lee Leahye20a3192017-03-09 16:21:34 -08001096 __gcov_flush();
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001097
Lee Leahye20a3192017-03-09 16:21:34 -08001098 va_start(ap, arg);
1099 va_copy(aq, ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001100
Lee Leahye20a3192017-03-09 16:21:34 -08001101 length = 2;
1102 while (va_arg(ap, char *))
1103 length++;
1104 va_end(ap);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001105
Lee Leahye20a3192017-03-09 16:21:34 -08001106 args = (char **) alloca(length * sizeof(void *));
1107 args[0] = arg;
1108 for (i = 1; i < length; i++)
1109 args[i] = va_arg(aq, char *);
1110 envp = va_arg(aq, char **);
1111 va_end(aq);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001112
Lee Leahye20a3192017-03-09 16:21:34 -08001113 return execve(path, args, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001114}
1115#endif
1116
1117#ifdef L_gcov_execv
1118/* A wrapper for the execv function. Flushes the accumulated profiling data, so
1119 that they are not lost. */
1120
1121int
Lee Leahy38768c32017-03-09 14:07:18 -08001122__gcov_execv(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001123{
Lee Leahye20a3192017-03-09 16:21:34 -08001124 __gcov_flush();
1125 return execv(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001126}
1127#endif
1128
1129#ifdef L_gcov_execvp
Lee Leahy73402172017-03-10 15:23:24 -08001130/* A wrapper for the execvp function. Flushes the accumulated profiling data,
1131 * so that they are not lost.
1132 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001133
1134int
Lee Leahy38768c32017-03-09 14:07:18 -08001135__gcov_execvp(const char *path, char *const argv[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001136{
Lee Leahye20a3192017-03-09 16:21:34 -08001137 __gcov_flush();
1138 return execvp(path, argv);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001139}
1140#endif
1141
1142#ifdef L_gcov_execve
Lee Leahy73402172017-03-10 15:23:24 -08001143/* A wrapper for the execve function. Flushes the accumulated profiling data,
1144 * so that they are not lost.
1145 */
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001146
1147int
Lee Leahy38768c32017-03-09 14:07:18 -08001148__gcov_execve(const char *path, char *const argv[], char *const envp[])
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001149{
Lee Leahye20a3192017-03-09 16:21:34 -08001150 __gcov_flush();
1151 return execve(path, argv, envp);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001152}
1153#endif
1154#endif /* inhibit_libc */