1/* Header file for libgcov-*.c.
2   Copyright (C) 1996-2022 Free Software Foundation, Inc.
3
4   This file is part of GCC.
5
6   GCC is free software; you can redistribute it and/or modify it under
7   the terms of the GNU General Public License as published by the Free
8   Software Foundation; either version 3, or (at your option) any later
9   version.
10
11   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   for more details.
15
16   Under Section 7 of GPL version 3, you are granted additional
17   permissions described in the GCC Runtime Library Exception, version
18   3.1, as published by the Free Software Foundation.
19
20   You should have received a copy of the GNU General Public License and
21   a copy of the GCC Runtime Library Exception along with this program;
22   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23   <http://www.gnu.org/licenses/>.  */
24
25#ifndef GCC_LIBGCOV_H
26#define GCC_LIBGCOV_H
27
28/* work around the poisoned malloc/calloc in system.h.  */
29#ifndef xmalloc
30#define xmalloc malloc
31#endif
32#ifndef xcalloc
33#define xcalloc calloc
34#endif
35
36#ifndef IN_GCOV_TOOL
37/* About the target.  */
38/* This path will be used by libgcov runtime.  */
39
40#include "tconfig.h"
41#include "auto-target.h"
42#include "tsystem.h"
43#include "coretypes.h"
44#include "tm.h"
45#include "libgcc_tm.h"
46#include "gcov.h"
47
48#if HAVE_SYS_MMAN_H
49#include <sys/mman.h>
50#endif
51
52#if __CHAR_BIT__ == 8
53typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
54typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
55#if __LIBGCC_GCOV_TYPE_SIZE > 32
56typedef signed gcov_type __attribute__ ((mode (DI)));
57typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
58#else
59typedef signed gcov_type __attribute__ ((mode (SI)));
60typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
61#endif
62#else
63#if __CHAR_BIT__ == 16
64typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
65typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
66#if __LIBGCC_GCOV_TYPE_SIZE > 32
67typedef signed gcov_type __attribute__ ((mode (SI)));
68typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
69#else
70typedef signed gcov_type __attribute__ ((mode (HI)));
71typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
72#endif
73#else
74typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
75typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
76#if __LIBGCC_GCOV_TYPE_SIZE > 32
77typedef signed gcov_type __attribute__ ((mode (HI)));
78typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
79#else
80typedef signed gcov_type __attribute__ ((mode (QI)));
81typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
82#endif
83#endif
84#endif
85
86#if defined (TARGET_POSIX_IO)
87#define GCOV_LOCKED 1
88#else
89#define GCOV_LOCKED 0
90#endif
91
92#if defined (__MSVCRT__)
93#define GCOV_LOCKED_WITH_LOCKING 1
94#else
95#define GCOV_LOCKED_WITH_LOCKING 0
96#endif
97
98#ifndef GCOV_SUPPORTS_ATOMIC
99/* Detect whether target can support atomic update of profilers.  */
100#if __SIZEOF_LONG_LONG__ == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
101#define GCOV_SUPPORTS_ATOMIC 1
102#else
103#if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
104#define GCOV_SUPPORTS_ATOMIC 1
105#else
106#define GCOV_SUPPORTS_ATOMIC 0
107#endif
108#endif
109#endif
110
111/* In libgcov we need these functions to be extern, so prefix them with
112   __gcov.  In libgcov they must also be hidden so that the instance in
113   the executable is not also used in a DSO.  */
114#define gcov_var __gcov_var
115#define gcov_open __gcov_open
116#define gcov_close __gcov_close
117#define gcov_position __gcov_position
118#define gcov_seek __gcov_seek
119#define gcov_rewrite __gcov_rewrite
120#define gcov_is_error __gcov_is_error
121#define gcov_write_unsigned __gcov_write_unsigned
122#define gcov_write_summary __gcov_write_summary
123#define gcov_read_unsigned __gcov_read_unsigned
124#define gcov_read_counter __gcov_read_counter
125#define gcov_read_summary __gcov_read_summary
126
127#else /* IN_GCOV_TOOL */
128/* About the host.  */
129/* This path will be compiled for the host and linked into
130   gcov-tool binary.  */
131
132#include "config.h"
133#include "system.h"
134#include "coretypes.h"
135#include "tm.h"
136
137typedef unsigned gcov_unsigned_t;
138typedef unsigned gcov_position_t;
139/* gcov_type is typedef'd elsewhere for the compiler */
140
141#if defined (HOST_HAS_F_SETLKW)
142#define GCOV_LOCKED 1
143#else
144#define GCOV_LOCKED 0
145#endif
146
147#if defined (HOST_HAS_LK_LOCK)
148#define GCOV_LOCKED_WITH_LOCKING 1
149#else
150#define GCOV_LOCKED_WITH_LOCKING 0
151#endif
152
153/* Some Macros specific to gcov-tool.  */
154
155#define L_gcov 1
156#define L_gcov_merge_add 1
157#define L_gcov_merge_topn 1
158#define L_gcov_merge_ior 1
159#define L_gcov_merge_time_profile 1
160
161extern gcov_type gcov_read_counter_mem ();
162extern unsigned gcov_get_merge_weight ();
163extern struct gcov_info *gcov_list;
164
165#endif /* !IN_GCOV_TOOL */
166
167#if defined(inhibit_libc)
168#define IN_LIBGCOV (-1)
169#else
170#define IN_LIBGCOV 1
171#if defined(L_gcov)
172#define GCOV_LINKAGE /* nothing */
173#endif
174#endif
175
176/* Poison these, so they don't accidentally slip in.  */
177#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
178#pragma GCC poison gcov_time
179
180#ifdef HAVE_GAS_HIDDEN
181#define ATTRIBUTE_HIDDEN  __attribute__ ((__visibility__ ("hidden")))
182#else
183#define ATTRIBUTE_HIDDEN
184#endif
185
186#if HAVE_SYS_MMAN_H
187#ifndef MAP_FAILED
188#define MAP_FAILED ((void *)-1)
189#endif
190
191#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
192#define MAP_ANONYMOUS MAP_ANON
193#endif
194#endif
195
196#include "gcov-io.h"
197
198/* Structures embedded in coveraged program.  The structures generated
199   by write_profile must match these.  */
200
201/* Information about counters for a single function.  */
202struct gcov_ctr_info
203{
204  gcov_unsigned_t num;		/* number of counters.  */
205  gcov_type *values;		/* their values.  */
206};
207
208/* Information about a single function.  This uses the trailing array
209   idiom. The number of counters is determined from the merge pointer
210   array in gcov_info.  The key is used to detect which of a set of
211   comdat functions was selected -- it points to the gcov_info object
212   of the object file containing the selected comdat function.  */
213
214struct gcov_fn_info
215{
216  const struct gcov_info *key;		/* comdat key */
217  gcov_unsigned_t ident;		/* unique ident of function */
218  gcov_unsigned_t lineno_checksum;	/* function lineo_checksum */
219  gcov_unsigned_t cfg_checksum;		/* function cfg checksum */
220  struct gcov_ctr_info ctrs[1];		/* instrumented counters */
221};
222
223/* Type of function used to merge counters.  */
224typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
225
226/* Information about a single object file.  */
227struct gcov_info
228{
229  gcov_unsigned_t version;	/* expected version number */
230  struct gcov_info *next;	/* link to next, used by libgcov */
231
232  gcov_unsigned_t stamp;	/* uniquifying time stamp */
233  gcov_unsigned_t checksum;	/* unique object checksum */
234  const char *filename;		/* output file name */
235
236  gcov_merge_fn merge[GCOV_COUNTERS];  /* merge functions (null for
237					  unused) */
238
239  gcov_unsigned_t n_functions;		/* number of functions */
240
241#ifndef IN_GCOV_TOOL
242  const struct gcov_fn_info *const *functions; /* pointer to pointers
243                                                  to function information  */
244#else
245  struct gcov_fn_info **functions;
246  struct gcov_summary summary;
247#endif /* !IN_GCOV_TOOL */
248};
249
250/* Root of a program/shared-object state */
251struct gcov_root
252{
253  struct gcov_info *list;
254  unsigned dumped : 1;	/* counts have been dumped.  */
255  unsigned run_counted : 1;  /* run has been accounted for.  */
256  struct gcov_root *next;
257  struct gcov_root *prev;
258};
259
260extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN;
261
262struct gcov_master
263{
264  gcov_unsigned_t version;
265  struct gcov_root *root;
266};
267
268struct indirect_call_tuple
269{
270  /* Callee function.  */
271  void *callee;
272
273  /* Pointer to counters.  */
274  gcov_type *counters;
275};
276
277/* Exactly one of these will be active in the process.  */
278extern struct gcov_master __gcov_master;
279extern struct gcov_kvp *__gcov_kvp_dynamic_pool;
280extern unsigned __gcov_kvp_dynamic_pool_index;
281extern unsigned __gcov_kvp_dynamic_pool_size;
282
283/* Dump a set of gcov objects.  */
284extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN;
285
286/* Register a new object file module.  */
287extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
288
289/* GCOV exit function registered via a static destructor.  */
290extern void __gcov_exit (void) ATTRIBUTE_HIDDEN;
291
292/* Function to reset all counters to 0.  Both externally visible (and
293   overridable) and internal version.  */
294extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN;
295
296/* User function to enable early write of profile information so far.  */
297extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN;
298
299/* Lock critical section for __gcov_dump and __gcov_reset functions.  */
300extern void __gcov_lock (void) ATTRIBUTE_HIDDEN;
301
302/* Unlock critical section for __gcov_dump and __gcov_reset functions.  */
303extern void __gcov_unlock (void) ATTRIBUTE_HIDDEN;
304
305/* The merge function that just sums the counters.  */
306extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
307
308/* The merge function to select the minimum valid counter value.  */
309extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
310
311/* The merge function to choose the most common N values.  */
312extern void __gcov_merge_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
313
314/* The merge function that just ors the counters together.  */
315extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
316
317/* The profiler functions.  */
318extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
319extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int,
320					     unsigned);
321extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
322extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type);
323extern void __gcov_topn_values_profiler (gcov_type *, gcov_type);
324extern void __gcov_topn_values_profiler_atomic (gcov_type *, gcov_type);
325extern void __gcov_indirect_call_profiler_v4 (gcov_type, void *);
326extern void __gcov_indirect_call_profiler_v4_atomic (gcov_type, void *);
327extern void __gcov_time_profiler (gcov_type *);
328extern void __gcov_time_profiler_atomic (gcov_type *);
329extern void __gcov_average_profiler (gcov_type *, gcov_type);
330extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
331extern void __gcov_ior_profiler (gcov_type *, gcov_type);
332extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
333
334#ifndef inhibit_libc
335/* The wrappers around some library functions..  */
336extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
337extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN;
338extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN;
339extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN;
340extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN;
341extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
342extern int __gcov_execve (const char *, char  *const [], char *const [])
343  ATTRIBUTE_HIDDEN;
344
345/* Functions that only available in libgcov.  */
346GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
347GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
348                                      const struct gcov_summary *)
349    ATTRIBUTE_HIDDEN;
350GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
351GCOV_LINKAGE void gcov_rewrite (void) ATTRIBUTE_HIDDEN;
352
353/* "Counts" stored in gcda files can be a real counter value, or
354   an target address. When differentiate these two types because
355   when manipulating counts, we should only change real counter values,
356   rather target addresses.  */
357
358static inline gcov_type
359gcov_get_counter (void)
360{
361#ifndef IN_GCOV_TOOL
362  /* This version is for reading count values in libgcov runtime:
363     we read from gcda files.  */
364
365  return gcov_read_counter ();
366#else
367  /* This version is for gcov-tool. We read the value from memory and
368     multiply it by the merge weight.  */
369
370  return gcov_read_counter_mem () * gcov_get_merge_weight ();
371#endif
372}
373
374/* Similar function as gcov_get_counter(), but do not scale
375   when read value is equal to IGNORE_SCALING.  */
376
377static inline gcov_type
378gcov_get_counter_ignore_scaling (gcov_type ignore_scaling ATTRIBUTE_UNUSED)
379{
380#ifndef IN_GCOV_TOOL
381  /* This version is for reading count values in libgcov runtime:
382     we read from gcda files.  */
383
384  return gcov_read_counter ();
385#else
386  /* This version is for gcov-tool. We read the value from memory and
387     multiply it by the merge weight.  */
388
389  gcov_type v = gcov_read_counter_mem ();
390  if (v != ignore_scaling)
391    v *= gcov_get_merge_weight ();
392
393  return v;
394#endif
395}
396
397/* Similar function as gcov_get_counter(), but handles target address
398   counters.  */
399
400static inline gcov_type
401gcov_get_counter_target (void)
402{
403#ifndef IN_GCOV_TOOL
404  /* This version is for reading count target values in libgcov runtime:
405     we read from gcda files.  */
406
407  return gcov_read_counter ();
408#else
409  /* This version is for gcov-tool.  We read the value from memory and we do NOT
410     multiply it by the merge weight.  */
411
412  return gcov_read_counter_mem ();
413#endif
414}
415
416/* Add VALUE to *COUNTER and make it with atomic operation
417   if USE_ATOMIC is true.  */
418
419static inline void
420gcov_counter_add (gcov_type *counter, gcov_type value,
421		  int use_atomic ATTRIBUTE_UNUSED)
422{
423#if GCOV_SUPPORTS_ATOMIC
424  if (use_atomic)
425    __atomic_fetch_add (counter, value, __ATOMIC_RELAXED);
426  else
427#endif
428    *counter += value;
429}
430
431#if HAVE_SYS_MMAN_H
432
433/* Allocate LENGTH with mmap function.  */
434
435static inline void *
436malloc_mmap (size_t length)
437{
438  return mmap (NULL, length, PROT_READ | PROT_WRITE,
439	       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
440}
441
442#endif
443
444/* Allocate gcov_kvp from statically pre-allocated pool,
445   or use heap otherwise.  */
446
447static inline struct gcov_kvp *
448allocate_gcov_kvp (void)
449{
450#define MMAP_CHUNK_SIZE	(128 * 1024)
451  struct gcov_kvp *new_node = NULL;
452  unsigned kvp_sizeof = sizeof(struct gcov_kvp);
453
454  /* Try mmaped pool if available.  */
455#if !defined(IN_GCOV_TOOL) && !defined(L_gcov_merge_topn) && HAVE_SYS_MMAN_H
456  if (__gcov_kvp_dynamic_pool == NULL
457      || __gcov_kvp_dynamic_pool_index >= __gcov_kvp_dynamic_pool_size)
458    {
459      void *ptr = malloc_mmap (MMAP_CHUNK_SIZE);
460      if (ptr != MAP_FAILED)
461	{
462	  __gcov_kvp_dynamic_pool = ptr;
463	  __gcov_kvp_dynamic_pool_size = MMAP_CHUNK_SIZE / kvp_sizeof;
464	  __gcov_kvp_dynamic_pool_index = 0;
465	}
466    }
467
468  if (__gcov_kvp_dynamic_pool != NULL)
469    {
470      unsigned index;
471#if GCOV_SUPPORTS_ATOMIC
472      index
473	= __atomic_fetch_add (&__gcov_kvp_dynamic_pool_index, 1,
474			      __ATOMIC_RELAXED);
475#else
476      index = __gcov_kvp_dynamic_pool_index++;
477#endif
478      if (index < __gcov_kvp_dynamic_pool_size)
479	new_node = __gcov_kvp_dynamic_pool + index;
480    }
481#endif
482
483  /* Fallback to malloc.  */
484  if (new_node == NULL)
485    new_node = (struct gcov_kvp *)xcalloc (1, kvp_sizeof);
486
487  return new_node;
488}
489
490/* Add key value pair VALUE:COUNT to a top N COUNTERS.  When INCREMENT_TOTAL
491   is true, add COUNT to total of the TOP counter.  If USE_ATOMIC is true,
492   do it in atomic way.  Return true when the counter is full, otherwise
493   return false.  */
494
495static inline unsigned
496gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count,
497		     int use_atomic, int increment_total)
498{
499  if (increment_total)
500    {
501      /* In the multi-threaded mode, we can have an already merged profile
502	 with a negative total value.  In that case, we should bail out.  */
503      if (counters[0] < 0)
504	return 0;
505      gcov_counter_add (&counters[0], 1, use_atomic);
506    }
507
508  struct gcov_kvp *prev_node = NULL;
509  struct gcov_kvp *minimal_node = NULL;
510  struct gcov_kvp *current_node  = (struct gcov_kvp *)(intptr_t)counters[2];
511
512  while (current_node)
513    {
514      if (current_node->value == value)
515	{
516	  gcov_counter_add (&current_node->count, count, use_atomic);
517	  return 0;
518	}
519
520      if (minimal_node == NULL
521	  || current_node->count < minimal_node->count)
522	minimal_node = current_node;
523
524      prev_node = current_node;
525      current_node = current_node->next;
526    }
527
528  if (counters[1] == GCOV_TOPN_MAXIMUM_TRACKED_VALUES)
529    {
530      if (--minimal_node->count < count)
531	{
532	  minimal_node->value = value;
533	  minimal_node->count = count;
534	}
535
536      return 1;
537    }
538  else
539    {
540      struct gcov_kvp *new_node = allocate_gcov_kvp ();
541      if (new_node == NULL)
542	return 0;
543
544      new_node->value = value;
545      new_node->count = count;
546
547      int success = 0;
548      if (!counters[2])
549	{
550#if GCOV_SUPPORTS_ATOMIC
551	  if (use_atomic)
552	    {
553	      struct gcov_kvp **ptr = (struct gcov_kvp **)(intptr_t)&counters[2];
554	      success = !__sync_val_compare_and_swap (ptr, 0, new_node);
555	    }
556	  else
557#endif
558	    {
559	      counters[2] = (intptr_t)new_node;
560	      success = 1;
561	    }
562	}
563      else if (prev_node && !prev_node->next)
564	{
565#if GCOV_SUPPORTS_ATOMIC
566	  if (use_atomic)
567	    success = !__sync_val_compare_and_swap (&prev_node->next, 0,
568						    new_node);
569	  else
570#endif
571	    {
572	      prev_node->next = new_node;
573	      success = 1;
574	    }
575	}
576
577      /* Increment number of nodes.  */
578      if (success)
579	gcov_counter_add (&counters[1], 1, use_atomic);
580    }
581
582  return 0;
583}
584
585#endif /* !inhibit_libc */
586
587#endif /* GCC_LIBGCOV_H */
588