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