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 (¤t_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