1 /* Header file for libgcov-*.c.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
4 This file is part of GCC.
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
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
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.
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/>. */
28 /* work around the poisoned malloc/calloc in system.h. */
30 #define xmalloc malloc
33 #define xcalloc calloc
37 /* About the target. */
38 /* This path will be used by libgcov runtime. */
41 #include "auto-target.h"
43 #include "coretypes.h"
45 #include "libgcc_tm.h"
53 typedef unsigned gcov_unsigned_t
__attribute__ ((mode (SI
)));
54 typedef unsigned gcov_position_t
__attribute__ ((mode (SI
)));
55 #if __LIBGCC_GCOV_TYPE_SIZE > 32
56 typedef signed gcov_type
__attribute__ ((mode (DI
)));
57 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (DI
)));
59 typedef signed gcov_type
__attribute__ ((mode (SI
)));
60 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (SI
)));
63 #if __CHAR_BIT__ == 16
64 typedef unsigned gcov_unsigned_t
__attribute__ ((mode (HI
)));
65 typedef unsigned gcov_position_t
__attribute__ ((mode (HI
)));
66 #if __LIBGCC_GCOV_TYPE_SIZE > 32
67 typedef signed gcov_type
__attribute__ ((mode (SI
)));
68 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (SI
)));
70 typedef signed gcov_type
__attribute__ ((mode (HI
)));
71 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (HI
)));
74 typedef unsigned gcov_unsigned_t
__attribute__ ((mode (QI
)));
75 typedef unsigned gcov_position_t
__attribute__ ((mode (QI
)));
76 #if __LIBGCC_GCOV_TYPE_SIZE > 32
77 typedef signed gcov_type
__attribute__ ((mode (HI
)));
78 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (HI
)));
80 typedef signed gcov_type
__attribute__ ((mode (QI
)));
81 typedef unsigned gcov_type_unsigned
__attribute__ ((mode (QI
)));
86 #if defined (TARGET_POSIX_IO)
92 #if defined (__MSVCRT__)
93 #define GCOV_LOCKED_WITH_LOCKING 1
95 #define GCOV_LOCKED_WITH_LOCKING 0
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
103 #if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
104 #define GCOV_SUPPORTS_ATOMIC 1
106 #define GCOV_SUPPORTS_ATOMIC 0
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
127 #else /* IN_GCOV_TOOL */
128 /* About the host. */
129 /* This path will be compiled for the host and linked into
134 #include "coretypes.h"
137 typedef unsigned gcov_unsigned_t
;
138 typedef unsigned gcov_position_t
;
139 /* gcov_type is typedef'd elsewhere for the compiler */
141 #if defined (HOST_HAS_F_SETLKW)
142 #define GCOV_LOCKED 1
144 #define GCOV_LOCKED 0
147 #if defined (HOST_HAS_LK_LOCK)
148 #define GCOV_LOCKED_WITH_LOCKING 1
150 #define GCOV_LOCKED_WITH_LOCKING 0
153 /* Some Macros specific to gcov-tool. */
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
161 extern gcov_type
gcov_read_counter_mem ();
162 extern unsigned gcov_get_merge_weight ();
163 extern struct gcov_info
*gcov_list
;
165 #endif /* !IN_GCOV_TOOL */
167 #if defined(inhibit_libc)
168 #define IN_LIBGCOV (-1)
172 #define GCOV_LINKAGE /* nothing */
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
180 #ifdef HAVE_GAS_HIDDEN
181 #define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
183 #define ATTRIBUTE_HIDDEN
188 #define MAP_FAILED ((void *)-1)
191 #if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
192 #define MAP_ANONYMOUS MAP_ANON
198 /* Structures embedded in coveraged program. The structures generated
199 by write_profile must match these. */
201 /* Information about counters for a single function. */
204 gcov_unsigned_t num
; /* number of counters. */
205 gcov_type
*values
; /* their values. */
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. */
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 */
223 /* Type of function used to merge counters. */
224 typedef void (*gcov_merge_fn
) (gcov_type
*, gcov_unsigned_t
);
226 /* Information about a single object file. */
229 gcov_unsigned_t version
; /* expected version number */
230 struct gcov_info
*next
; /* link to next, used by libgcov */
232 gcov_unsigned_t stamp
; /* uniquifying time stamp */
233 gcov_unsigned_t checksum
; /* unique object checksum */
234 const char *filename
; /* output file name */
236 gcov_merge_fn merge
[GCOV_COUNTERS
]; /* merge functions (null for
239 unsigned n_functions
; /* number of functions */
242 const struct gcov_fn_info
*const *functions
; /* pointer to pointers
243 to function information */
245 struct gcov_fn_info
**functions
;
246 struct gcov_summary summary
;
247 #endif /* !IN_GCOV_TOOL */
250 /* Root of a program/shared-object state */
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
;
260 extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN
;
264 gcov_unsigned_t version
;
265 struct gcov_root
*root
;
268 struct indirect_call_tuple
270 /* Callee function. */
273 /* Pointer to counters. */
277 /* Exactly one of these will be active in the process. */
278 extern struct gcov_master __gcov_master
;
279 extern struct gcov_kvp
*__gcov_kvp_dynamic_pool
;
280 extern unsigned __gcov_kvp_dynamic_pool_index
;
281 extern unsigned __gcov_kvp_dynamic_pool_size
;
283 /* Dump a set of gcov objects. */
284 extern void __gcov_dump_one (struct gcov_root
*) ATTRIBUTE_HIDDEN
;
286 /* Register a new object file module. */
287 extern void __gcov_init (struct gcov_info
*) ATTRIBUTE_HIDDEN
;
289 /* GCOV exit function registered via a static destructor. */
290 extern void __gcov_exit (void) ATTRIBUTE_HIDDEN
;
292 /* Function to reset all counters to 0. Both externally visible (and
293 overridable) and internal version. */
294 extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN
;
296 /* User function to enable early write of profile information so far. */
297 extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN
;
299 /* Lock critical section for __gcov_dump and __gcov_reset functions. */
300 extern void __gcov_lock (void) ATTRIBUTE_HIDDEN
;
302 /* Unlock critical section for __gcov_dump and __gcov_reset functions. */
303 extern void __gcov_unlock (void) ATTRIBUTE_HIDDEN
;
305 /* The merge function that just sums the counters. */
306 extern void __gcov_merge_add (gcov_type
*, unsigned) ATTRIBUTE_HIDDEN
;
308 /* The merge function to select the minimum valid counter value. */
309 extern void __gcov_merge_time_profile (gcov_type
*, unsigned) ATTRIBUTE_HIDDEN
;
311 /* The merge function to choose the most common N values. */
312 extern void __gcov_merge_topn (gcov_type
*, unsigned) ATTRIBUTE_HIDDEN
;
314 /* The merge function that just ors the counters together. */
315 extern void __gcov_merge_ior (gcov_type
*, unsigned) ATTRIBUTE_HIDDEN
;
317 /* The profiler functions. */
318 extern void __gcov_interval_profiler (gcov_type
*, gcov_type
, int, unsigned);
319 extern void __gcov_interval_profiler_atomic (gcov_type
*, gcov_type
, int,
321 extern void __gcov_pow2_profiler (gcov_type
*, gcov_type
);
322 extern void __gcov_pow2_profiler_atomic (gcov_type
*, gcov_type
);
323 extern void __gcov_topn_values_profiler (gcov_type
*, gcov_type
);
324 extern void __gcov_topn_values_profiler_atomic (gcov_type
*, gcov_type
);
325 extern void __gcov_indirect_call_profiler_v4 (gcov_type
, void *);
326 extern void __gcov_indirect_call_profiler_v4_atomic (gcov_type
, void *);
327 extern void __gcov_time_profiler (gcov_type
*);
328 extern void __gcov_time_profiler_atomic (gcov_type
*);
329 extern void __gcov_average_profiler (gcov_type
*, gcov_type
);
330 extern void __gcov_average_profiler_atomic (gcov_type
*, gcov_type
);
331 extern void __gcov_ior_profiler (gcov_type
*, gcov_type
);
332 extern void __gcov_ior_profiler_atomic (gcov_type
*, gcov_type
);
335 /* The wrappers around some library functions.. */
336 extern pid_t
__gcov_fork (void) ATTRIBUTE_HIDDEN
;
337 extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN
;
338 extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN
;
339 extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN
;
340 extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN
;
341 extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN
;
342 extern int __gcov_execve (const char *, char *const [], char *const [])
345 /* Functions that only available in libgcov. */
346 GCOV_LINKAGE
int gcov_open (const char */
*name*/
) ATTRIBUTE_HIDDEN
;
347 GCOV_LINKAGE
void gcov_write_summary (gcov_unsigned_t
/*tag*/,
348 const struct gcov_summary
*)
350 GCOV_LINKAGE
void gcov_seek (gcov_position_t
/*position*/) ATTRIBUTE_HIDDEN
;
351 GCOV_LINKAGE
void gcov_rewrite (void) ATTRIBUTE_HIDDEN
;
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. */
358 static inline gcov_type
359 gcov_get_counter (void)
362 /* This version is for reading count values in libgcov runtime:
363 we read from gcda files. */
365 return gcov_read_counter ();
367 /* This version is for gcov-tool. We read the value from memory and
368 multiply it by the merge weight. */
370 return gcov_read_counter_mem () * gcov_get_merge_weight ();
374 /* Similar function as gcov_get_counter(), but do not scale
375 when read value is equal to IGNORE_SCALING. */
377 static inline gcov_type
378 gcov_get_counter_ignore_scaling (gcov_type ignore_scaling ATTRIBUTE_UNUSED
)
381 /* This version is for reading count values in libgcov runtime:
382 we read from gcda files. */
384 return gcov_read_counter ();
386 /* This version is for gcov-tool. We read the value from memory and
387 multiply it by the merge weight. */
389 gcov_type v
= gcov_read_counter_mem ();
390 if (v
!= ignore_scaling
)
391 v
*= gcov_get_merge_weight ();
397 /* Similar function as gcov_get_counter(), but handles target address
400 static inline gcov_type
401 gcov_get_counter_target (void)
404 /* This version is for reading count target values in libgcov runtime:
405 we read from gcda files. */
407 return gcov_read_counter ();
409 /* This version is for gcov-tool. We read the value from memory and we do NOT
410 multiply it by the merge weight. */
412 return gcov_read_counter_mem ();
416 /* Add VALUE to *COUNTER and make it with atomic operation
417 if USE_ATOMIC is true. */
420 gcov_counter_add (gcov_type
*counter
, gcov_type value
,
421 int use_atomic ATTRIBUTE_UNUSED
)
423 #if GCOV_SUPPORTS_ATOMIC
425 __atomic_fetch_add (counter
, value
, __ATOMIC_RELAXED
);
433 /* Allocate LENGTH with mmap function. */
436 malloc_mmap (size_t length
)
438 return mmap (NULL
, length
, PROT_READ
| PROT_WRITE
,
439 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
444 /* Allocate gcov_kvp from statically pre-allocated pool,
445 or use heap otherwise. */
447 static inline struct gcov_kvp
*
448 allocate_gcov_kvp (void)
450 #define MMAP_CHUNK_SIZE (128 * 1024)
451 struct gcov_kvp
*new_node
= NULL
;
452 unsigned kvp_sizeof
= sizeof(struct gcov_kvp
);
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
)
459 void *ptr
= malloc_mmap (MMAP_CHUNK_SIZE
);
460 if (ptr
!= MAP_FAILED
)
462 __gcov_kvp_dynamic_pool
= ptr
;
463 __gcov_kvp_dynamic_pool_size
= MMAP_CHUNK_SIZE
/ kvp_sizeof
;
464 __gcov_kvp_dynamic_pool_index
= 0;
468 if (__gcov_kvp_dynamic_pool
!= NULL
)
471 #if GCOV_SUPPORTS_ATOMIC
473 = __atomic_fetch_add (&__gcov_kvp_dynamic_pool_index
, 1,
476 index
= __gcov_kvp_dynamic_pool_index
++;
478 if (index
< __gcov_kvp_dynamic_pool_size
)
479 new_node
= __gcov_kvp_dynamic_pool
+ index
;
483 /* Fallback to malloc. */
484 if (new_node
== NULL
)
485 new_node
= (struct gcov_kvp
*)xcalloc (1, kvp_sizeof
);
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
495 static inline unsigned
496 gcov_topn_add_value (gcov_type
*counters
, gcov_type value
, gcov_type count
,
497 int use_atomic
, int increment_total
)
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. */
505 gcov_counter_add (&counters
[0], 1, use_atomic
);
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];
514 if (current_node
->value
== value
)
516 gcov_counter_add (¤t_node
->count
, count
, use_atomic
);
520 if (minimal_node
== NULL
521 || current_node
->count
< minimal_node
->count
)
522 minimal_node
= current_node
;
524 prev_node
= current_node
;
525 current_node
= current_node
->next
;
528 if (counters
[1] == GCOV_TOPN_MAXIMUM_TRACKED_VALUES
)
530 if (--minimal_node
->count
< count
)
532 minimal_node
->value
= value
;
533 minimal_node
->count
= count
;
540 struct gcov_kvp
*new_node
= allocate_gcov_kvp ();
541 if (new_node
== NULL
)
544 new_node
->value
= value
;
545 new_node
->count
= count
;
550 #if GCOV_SUPPORTS_ATOMIC
553 struct gcov_kvp
**ptr
= (struct gcov_kvp
**)(intptr_t)&counters
[2];
554 success
= !__sync_val_compare_and_swap (ptr
, 0, new_node
);
559 counters
[2] = (intptr_t)new_node
;
563 else if (prev_node
&& !prev_node
->next
)
565 #if GCOV_SUPPORTS_ATOMIC
567 success
= !__sync_val_compare_and_swap (&prev_node
->next
, 0,
572 prev_node
->next
= new_node
;
577 /* Increment number of nodes. */
579 gcov_counter_add (&counters
[1], 1, use_atomic
);
585 #endif /* !inhibit_libc */
587 #endif /* GCC_LIBGCOV_H */